xref: /openbmc/qemu/hw/misc/ibm-cffps.c (revision 46f3d6a16b2cbdf75f068e56b422dc05ccfdbe1b)
1*46f3d6a1SCédric Le Goater /*
2*46f3d6a1SCédric Le Goater  * IBM CFF power supplies device
3*46f3d6a1SCédric Le Goater  *
4*46f3d6a1SCédric Le Goater  * Copyright (c) 2019 IBM Corporation.
5*46f3d6a1SCédric Le Goater  *
6*46f3d6a1SCédric Le Goater  * This code is licensed under the GPL version 2 or later. See the
7*46f3d6a1SCédric Le Goater  * COPYING file in the top-level directory.
8*46f3d6a1SCédric Le Goater  */
9*46f3d6a1SCédric Le Goater 
10*46f3d6a1SCédric Le Goater #include "qemu/osdep.h"
11*46f3d6a1SCédric Le Goater #include "hw/hw.h"
12*46f3d6a1SCédric Le Goater #include "hw/i2c/i2c.h"
13*46f3d6a1SCédric Le Goater #include "qapi/error.h"
14*46f3d6a1SCédric Le Goater #include "qapi/visitor.h"
15*46f3d6a1SCédric Le Goater #include "hw/misc/pmbus_regs.h"
16*46f3d6a1SCédric Le Goater #include "migration/vmstate.h"
17*46f3d6a1SCédric Le Goater 
18*46f3d6a1SCédric Le Goater #define CFFPS_CCIN                              0xBD
19*46f3d6a1SCédric Le Goater #define CFFPS_FW_CMD_START                      0xFA
20*46f3d6a1SCédric Le Goater #define CFFPS_FW_NUM_BYTES                      4
21*46f3d6a1SCédric Le Goater #define CFFPS_SYS_CONFIG                        0xDA
22*46f3d6a1SCédric Le Goater #define CFFPS_INPUT_HISTORY                     0xD6
23*46f3d6a1SCédric Le Goater #define CFFPS_INPUT_HISTORY_SIZE                100
24*46f3d6a1SCédric Le Goater 
25*46f3d6a1SCédric Le Goater #define FW_VERSION      0x04030201
26*46f3d6a1SCédric Le Goater #define CCIN            0x2B1D
27*46f3d6a1SCédric Le Goater 
28*46f3d6a1SCédric Le Goater typedef struct IBMCffpsState {
29*46f3d6a1SCédric Le Goater     /*< private >*/
30*46f3d6a1SCédric Le Goater     I2CSlave i2c;
31*46f3d6a1SCédric Le Goater     /*< public >*/
32*46f3d6a1SCédric Le Goater 
33*46f3d6a1SCédric Le Goater     uint8_t regs[0x100];
34*46f3d6a1SCédric Le Goater 
35*46f3d6a1SCédric Le Goater     uint8_t len;
36*46f3d6a1SCédric Le Goater     uint8_t buf[32];
37*46f3d6a1SCédric Le Goater     uint8_t pointer;
38*46f3d6a1SCédric Le Goater 
39*46f3d6a1SCédric Le Goater } IBMCffpsState;
40*46f3d6a1SCédric Le Goater 
41*46f3d6a1SCédric Le Goater #define TYPE_IBM_CFFPS "ibm-cffps"
42*46f3d6a1SCédric Le Goater #define IBM_CFFPS(obj) OBJECT_CHECK(IBMCffpsState, (obj), TYPE_IBM_CFFPS)
43*46f3d6a1SCédric Le Goater 
ibm_cffps_read(IBMCffpsState * s)44*46f3d6a1SCédric Le Goater static void ibm_cffps_read(IBMCffpsState *s)
45*46f3d6a1SCédric Le Goater {
46*46f3d6a1SCédric Le Goater     s->len = 0;
47*46f3d6a1SCédric Le Goater 
48*46f3d6a1SCédric Le Goater     switch (s->pointer) {
49*46f3d6a1SCédric Le Goater     case PMBUS_MFR_MODEL: /* FRU */
50*46f3d6a1SCédric Le Goater         s->buf[s->len++] = 7;  /* Byte count */
51*46f3d6a1SCédric Le Goater         s->buf[s->len++] = 'F';
52*46f3d6a1SCédric Le Goater         s->buf[s->len++] = 'R';
53*46f3d6a1SCédric Le Goater         s->buf[s->len++] = 'U';
54*46f3d6a1SCédric Le Goater         s->buf[s->len++] = '0';
55*46f3d6a1SCédric Le Goater         s->buf[s->len++] = '1';
56*46f3d6a1SCédric Le Goater         s->buf[s->len++] = '2';
57*46f3d6a1SCédric Le Goater         s->buf[s->len++] = '3';
58*46f3d6a1SCédric Le Goater         break;
59*46f3d6a1SCédric Le Goater     case PMBUS_MFR_REVISION: /* PART NUMBER */
60*46f3d6a1SCédric Le Goater         s->buf[s->len++] = 7;   /* Byte count */
61*46f3d6a1SCédric Le Goater         s->buf[s->len++] = 'P';
62*46f3d6a1SCédric Le Goater         s->buf[s->len++] = 'A';
63*46f3d6a1SCédric Le Goater         s->buf[s->len++] = 'R';
64*46f3d6a1SCédric Le Goater         s->buf[s->len++] = '0';
65*46f3d6a1SCédric Le Goater         s->buf[s->len++] = '1';
66*46f3d6a1SCédric Le Goater         s->buf[s->len++] = '2';
67*46f3d6a1SCédric Le Goater         s->buf[s->len++] = '3';
68*46f3d6a1SCédric Le Goater         break;
69*46f3d6a1SCédric Le Goater     case PMBUS_MFR_SERIAL:
70*46f3d6a1SCédric Le Goater         s->buf[s->len++] = 6;   /* Byte count */
71*46f3d6a1SCédric Le Goater         s->buf[s->len++] = 'X';
72*46f3d6a1SCédric Le Goater         s->buf[s->len++] = 'Y';
73*46f3d6a1SCédric Le Goater         s->buf[s->len++] = 'Z';
74*46f3d6a1SCédric Le Goater         s->buf[s->len++] = '0';
75*46f3d6a1SCédric Le Goater         s->buf[s->len++] = '1';
76*46f3d6a1SCédric Le Goater         s->buf[s->len++] = '2';
77*46f3d6a1SCédric Le Goater         break;
78*46f3d6a1SCédric Le Goater     case CFFPS_CCIN:
79*46f3d6a1SCédric Le Goater         s->buf[s->len++] = (CCIN >> 8) & 0xFF;
80*46f3d6a1SCédric Le Goater         s->buf[s->len++] = CCIN & 0xFF;
81*46f3d6a1SCédric Le Goater         break;
82*46f3d6a1SCédric Le Goater     case CFFPS_FW_CMD_START ... CFFPS_FW_CMD_START + CFFPS_FW_NUM_BYTES - 1:
83*46f3d6a1SCédric Le Goater         s->buf[s->len++] = (FW_VERSION >> (CFFPS_FW_NUM_BYTES -
84*46f3d6a1SCédric Le Goater                            (s->pointer - CFFPS_FW_CMD_START) - 1) * 8) & 0xFF;
85*46f3d6a1SCédric Le Goater         break;
86*46f3d6a1SCédric Le Goater     case CFFPS_INPUT_HISTORY: /* TODO */
87*46f3d6a1SCédric Le Goater         s->buf[s->len++] = 0x0;
88*46f3d6a1SCédric Le Goater         break;
89*46f3d6a1SCédric Le Goater     default:
90*46f3d6a1SCédric Le Goater         s->buf[s->len++] = s->regs[s->pointer];
91*46f3d6a1SCédric Le Goater         break;
92*46f3d6a1SCédric Le Goater     }
93*46f3d6a1SCédric Le Goater }
94*46f3d6a1SCédric Le Goater 
ibm_cffps_write(IBMCffpsState * s)95*46f3d6a1SCédric Le Goater static void ibm_cffps_write(IBMCffpsState *s)
96*46f3d6a1SCédric Le Goater {
97*46f3d6a1SCédric Le Goater     switch (s->pointer) {
98*46f3d6a1SCédric Le Goater     case CFFPS_SYS_CONFIG:
99*46f3d6a1SCédric Le Goater         s->regs[s->pointer] = s->buf[0];
100*46f3d6a1SCédric Le Goater         break;
101*46f3d6a1SCédric Le Goater     }
102*46f3d6a1SCédric Le Goater }
103*46f3d6a1SCédric Le Goater 
ibm_cffps_recv(I2CSlave * i2c)104*46f3d6a1SCédric Le Goater static uint8_t ibm_cffps_recv(I2CSlave *i2c)
105*46f3d6a1SCédric Le Goater {
106*46f3d6a1SCédric Le Goater     IBMCffpsState *s = IBM_CFFPS(i2c);
107*46f3d6a1SCédric Le Goater 
108*46f3d6a1SCédric Le Goater     if (s->len < sizeof(s->buf)) {
109*46f3d6a1SCédric Le Goater         return s->buf[s->len++];
110*46f3d6a1SCédric Le Goater     } else {
111*46f3d6a1SCédric Le Goater         return 0xff;
112*46f3d6a1SCédric Le Goater     }
113*46f3d6a1SCédric Le Goater }
114*46f3d6a1SCédric Le Goater 
ibm_cffps_send(I2CSlave * i2c,uint8_t data)115*46f3d6a1SCédric Le Goater static int ibm_cffps_send(I2CSlave *i2c, uint8_t data)
116*46f3d6a1SCédric Le Goater {
117*46f3d6a1SCédric Le Goater     IBMCffpsState *s = IBM_CFFPS(i2c);
118*46f3d6a1SCédric Le Goater 
119*46f3d6a1SCédric Le Goater     if (s->len == 0) {
120*46f3d6a1SCédric Le Goater         /*
121*46f3d6a1SCédric Le Goater          * first byte is the register pointer for a read or write
122*46f3d6a1SCédric Le Goater          * operation
123*46f3d6a1SCédric Le Goater          */
124*46f3d6a1SCédric Le Goater         s->pointer = data;
125*46f3d6a1SCédric Le Goater         s->len++;
126*46f3d6a1SCédric Le Goater     } else {
127*46f3d6a1SCédric Le Goater         /*
128*46f3d6a1SCédric Le Goater          * next bytes are data to write.
129*46f3d6a1SCédric Le Goater          */
130*46f3d6a1SCédric Le Goater         if (s->len <= sizeof(s->buf)) {
131*46f3d6a1SCédric Le Goater             s->buf[s->len - 1] = data;
132*46f3d6a1SCédric Le Goater         }
133*46f3d6a1SCédric Le Goater         s->len++;
134*46f3d6a1SCédric Le Goater         ibm_cffps_write(s);
135*46f3d6a1SCédric Le Goater     }
136*46f3d6a1SCédric Le Goater 
137*46f3d6a1SCédric Le Goater     return 0;
138*46f3d6a1SCédric Le Goater }
139*46f3d6a1SCédric Le Goater 
ibm_cffps_event(I2CSlave * i2c,enum i2c_event event)140*46f3d6a1SCédric Le Goater static int ibm_cffps_event(I2CSlave *i2c, enum i2c_event event)
141*46f3d6a1SCédric Le Goater {
142*46f3d6a1SCédric Le Goater     IBMCffpsState *s = IBM_CFFPS(i2c);
143*46f3d6a1SCédric Le Goater 
144*46f3d6a1SCédric Le Goater     /* TODO: handle SMBus "block read" */
145*46f3d6a1SCédric Le Goater 
146*46f3d6a1SCédric Le Goater     switch (event) {
147*46f3d6a1SCédric Le Goater     case I2C_START_RECV:
148*46f3d6a1SCédric Le Goater         ibm_cffps_read(s);
149*46f3d6a1SCédric Le Goater         break;
150*46f3d6a1SCédric Le Goater     case I2C_START_SEND:
151*46f3d6a1SCédric Le Goater     case I2C_NACK:
152*46f3d6a1SCédric Le Goater     case I2C_FINISH:
153*46f3d6a1SCédric Le Goater          s->pointer = 0xFF;
154*46f3d6a1SCédric Le Goater         break;
155*46f3d6a1SCédric Le Goater     default:
156*46f3d6a1SCédric Le Goater         return -1;
157*46f3d6a1SCédric Le Goater     }
158*46f3d6a1SCédric Le Goater 
159*46f3d6a1SCédric Le Goater     s->len = 0;
160*46f3d6a1SCédric Le Goater     return 0;
161*46f3d6a1SCédric Le Goater }
162*46f3d6a1SCédric Le Goater 
163*46f3d6a1SCédric Le Goater static const VMStateDescription vmstate_ibm_cffps = {
164*46f3d6a1SCédric Le Goater     .name = TYPE_IBM_CFFPS,
165*46f3d6a1SCédric Le Goater     .version_id = 0,
166*46f3d6a1SCédric Le Goater     .minimum_version_id = 0,
167*46f3d6a1SCédric Le Goater     .fields = (VMStateField[]) {
168*46f3d6a1SCédric Le Goater         VMSTATE_UINT8(len, IBMCffpsState),
169*46f3d6a1SCédric Le Goater         VMSTATE_UINT8_ARRAY(buf, IBMCffpsState, 32),
170*46f3d6a1SCédric Le Goater         VMSTATE_UINT8(pointer, IBMCffpsState),
171*46f3d6a1SCédric Le Goater         VMSTATE_UINT8_ARRAY(regs, IBMCffpsState, 0x100),
172*46f3d6a1SCédric Le Goater         VMSTATE_I2C_SLAVE(i2c, IBMCffpsState),
173*46f3d6a1SCédric Le Goater         VMSTATE_END_OF_LIST()
174*46f3d6a1SCédric Le Goater     }
175*46f3d6a1SCédric Le Goater };
176*46f3d6a1SCédric Le Goater 
ibm_cffps_reset(DeviceState * dev)177*46f3d6a1SCédric Le Goater static void ibm_cffps_reset(DeviceState *dev)
178*46f3d6a1SCédric Le Goater {
179*46f3d6a1SCédric Le Goater     IBMCffpsState *s = IBM_CFFPS(dev);
180*46f3d6a1SCédric Le Goater 
181*46f3d6a1SCédric Le Goater     memset(s->regs, 0, sizeof(s->regs));
182*46f3d6a1SCédric Le Goater     s->pointer = 0xFF;
183*46f3d6a1SCédric Le Goater }
184*46f3d6a1SCédric Le Goater 
ibm_cffps_realize(DeviceState * dev,Error ** errp)185*46f3d6a1SCédric Le Goater static void ibm_cffps_realize(DeviceState *dev, Error **errp)
186*46f3d6a1SCédric Le Goater {
187*46f3d6a1SCédric Le Goater     ;
188*46f3d6a1SCédric Le Goater }
189*46f3d6a1SCédric Le Goater 
ibm_cffps_class_init(ObjectClass * klass,void * data)190*46f3d6a1SCédric Le Goater static void ibm_cffps_class_init(ObjectClass *klass, void *data)
191*46f3d6a1SCédric Le Goater {
192*46f3d6a1SCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(klass);
193*46f3d6a1SCédric Le Goater     I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
194*46f3d6a1SCédric Le Goater 
195*46f3d6a1SCédric Le Goater     dc->realize = ibm_cffps_realize;
196*46f3d6a1SCédric Le Goater     device_class_set_legacy_reset(dc, ibm_cffps_reset);
197*46f3d6a1SCédric Le Goater     k->event = ibm_cffps_event;
198*46f3d6a1SCédric Le Goater     k->recv = ibm_cffps_recv;
199*46f3d6a1SCédric Le Goater     k->send = ibm_cffps_send;
200*46f3d6a1SCédric Le Goater     dc->vmsd = &vmstate_ibm_cffps;
201*46f3d6a1SCédric Le Goater }
202*46f3d6a1SCédric Le Goater 
203*46f3d6a1SCédric Le Goater static const TypeInfo ibm_cffps_info = {
204*46f3d6a1SCédric Le Goater     .name          = TYPE_IBM_CFFPS,
205*46f3d6a1SCédric Le Goater     .parent        = TYPE_I2C_SLAVE,
206*46f3d6a1SCédric Le Goater     .instance_size = sizeof(IBMCffpsState),
207*46f3d6a1SCédric Le Goater     .class_init    = ibm_cffps_class_init,
208*46f3d6a1SCédric Le Goater };
209*46f3d6a1SCédric Le Goater 
ibm_cffps_register_types(void)210*46f3d6a1SCédric Le Goater static void ibm_cffps_register_types(void)
211*46f3d6a1SCédric Le Goater {
212*46f3d6a1SCédric Le Goater     type_register_static(&ibm_cffps_info);
213*46f3d6a1SCédric Le Goater }
214*46f3d6a1SCédric Le Goater 
215*46f3d6a1SCédric Le Goater type_init(ibm_cffps_register_types)
216