1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <console/console.h>
4 #include <device/device.h>
9 #define IPMI_KCS_STATE(_x) ((_x) >> 6)
11 #define IPMI_KCS_GET_STATUS_ABORT 0x60
12 #define IPMI_KCS_START_WRITE 0x61
13 #define IPMI_KCS_END_WRITE 0x62
14 #define IPMI_KCS_READ_BYTE 0x68
16 #define IPMI_KCS_OBF 0x01
17 #define IPMI_KCS_IBF 0x02
18 #define IPMI_KCS_ATN 0x04
20 #define IPMI_KCS_STATE_IDLE 0x00
21 #define IPMI_KCS_STATE_READ 0x01
22 #define IPMI_KCS_STATE_WRITE 0x02
23 #define IPMI_KCS_STATE_ERROR 0x03
25 #define IPMI_CMD(_x) ((_x) + CONFIG_IPMI_KCS_REGISTER_SPACING)
26 #define IPMI_DATA(_x) ((_x))
27 #define IPMI_STAT(_x) ((_x) + CONFIG_IPMI_KCS_REGISTER_SPACING)
29 static unsigned char ipmi_kcs_status(int port
)
31 unsigned char status
= inb(IPMI_STAT(port
));
32 if (CONFIG(DEBUG_IPMI
))
33 printk(BIOS_SPEW
, "%s: 0x%02x\n", __func__
, status
);
37 static int wait_ibf_timeout(int port
)
39 if (!wait_ms(CONFIG_IPMI_KCS_TIMEOUT_MS
, !(ipmi_kcs_status(port
) & IPMI_KCS_IBF
))) {
40 printk(BIOS_ERR
, "wait_ibf timeout!\n");
47 static int wait_obf_timeout(int port
)
49 if (!wait_ms(CONFIG_IPMI_KCS_TIMEOUT_MS
, (ipmi_kcs_status(port
) & IPMI_KCS_OBF
))) {
50 printk(BIOS_ERR
, "wait_obf timeout!\n");
57 static int ipmi_kcs_send_data_byte(int port
, const unsigned char byte
)
61 if (CONFIG(DEBUG_IPMI
))
62 printk(BIOS_SPEW
, "%s: 0x%02x\n", __func__
, byte
);
64 outb(byte
, IPMI_DATA(port
));
66 if (wait_ibf_timeout(port
))
69 status
= ipmi_kcs_status(port
);
70 if ((status
& IPMI_KCS_OBF
) &&
71 IPMI_KCS_STATE(status
) != IPMI_KCS_STATE_WRITE
) {
72 printk(BIOS_ERR
, "%s: status %02x\n", __func__
, status
);
76 if (ipmi_kcs_status(port
) & IPMI_KCS_OBF
)
81 static int ipmi_kcs_send_last_data_byte(int port
, const unsigned char byte
)
85 if (CONFIG(DEBUG_IPMI
))
86 printk(BIOS_SPEW
, "%s: 0x%02x\n", __func__
, byte
);
88 if (wait_ibf_timeout(port
))
91 status
= ipmi_kcs_status(port
);
92 if ((status
& IPMI_KCS_OBF
) &&
93 IPMI_KCS_STATE(status
) != IPMI_KCS_STATE_WRITE
) {
94 printk(BIOS_ERR
, "%s: status %02x\n", __func__
, status
);
98 if (ipmi_kcs_status(port
) & IPMI_KCS_OBF
)
101 outb(byte
, IPMI_DATA(port
));
105 static int ipmi_kcs_send_cmd_byte(int port
, const unsigned char byte
)
107 if (CONFIG(DEBUG_IPMI
))
108 printk(BIOS_SPEW
, "%s: 0x%02x\n", __func__
, byte
);
110 if (wait_ibf_timeout(port
))
113 if (ipmi_kcs_status(port
) & IPMI_KCS_OBF
)
114 inb(IPMI_DATA(port
));
115 outb(byte
, IPMI_CMD(port
));
117 if (wait_ibf_timeout(port
))
120 if (ipmi_kcs_status(port
) & IPMI_KCS_OBF
)
121 inb(IPMI_DATA(port
));
126 static int ipmi_kcs_send_message(int port
, int netfn
, int lun
, int cmd
,
127 const unsigned char *msg
, int len
)
131 ret
= ipmi_kcs_send_cmd_byte(port
, IPMI_KCS_START_WRITE
);
133 printk(BIOS_ERR
, "IPMI START WRITE failed\n");
137 ret
= ipmi_kcs_send_data_byte(port
, (netfn
<< 2) | (lun
& 3));
139 printk(BIOS_ERR
, "IPMI NETFN failed\n");
144 ret
= ipmi_kcs_send_cmd_byte(port
, IPMI_KCS_END_WRITE
);
146 printk(BIOS_ERR
, "IPMI END WRITE failed\n");
150 ret
= ipmi_kcs_send_last_data_byte(port
, cmd
);
152 printk(BIOS_ERR
, "IPMI BYTE WRITE failed\n");
156 ret
= ipmi_kcs_send_data_byte(port
, cmd
);
158 printk(BIOS_ERR
, "IPMI CMD failed\n");
163 ret
= ipmi_kcs_send_data_byte(port
, *msg
++);
165 printk(BIOS_ERR
, "IPMI BYTE WRITE failed\n");
171 ret
= ipmi_kcs_send_cmd_byte(port
, IPMI_KCS_END_WRITE
);
173 printk(BIOS_ERR
, "IPMI END WRITE failed\n");
177 ret
= ipmi_kcs_send_last_data_byte(port
, *msg
);
179 printk(BIOS_ERR
, "IPMI BYTE WRITE failed\n");
187 static int ipmi_kcs_read_message(int port
, unsigned char *msg
, int len
)
191 if (wait_ibf_timeout(port
))
195 status
= ipmi_kcs_status(port
);
197 if (IPMI_KCS_STATE(status
) == IPMI_KCS_STATE_IDLE
)
200 if (IPMI_KCS_STATE(status
) != IPMI_KCS_STATE_READ
) {
201 printk(BIOS_ERR
, "%s: wrong state: 0x%02x\n", __func__
,
206 if (wait_obf_timeout(port
))
209 if (msg
&& (ret
< len
)) {
210 *msg
++ = inb(IPMI_DATA(port
));
214 if (wait_ibf_timeout(port
))
217 outb(IPMI_KCS_READ_BYTE
, IPMI_DATA(port
));
222 int ipmi_message(int port
, int netfn
, int lun
, int cmd
,
223 const unsigned char *inmsg
, int inlen
,
224 unsigned char *outmsg
, int outlen
)
226 if (ipmi_kcs_send_message(port
, netfn
, lun
, cmd
, inmsg
, inlen
)) {
227 printk(BIOS_ERR
, "ipmi_kcs_send_message failed\n");
231 return ipmi_kcs_read_message(port
, outmsg
, outlen
);