2 * This file is part of the coreboot project.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; version 2 of
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 * Place in devicetree.cb:
19 * device pnp ca2.0 on end # IPMI KCS
23 #include <console/console.h>
24 #include <device/device.h>
25 #include <device/pnp.h>
26 #if CONFIG(HAVE_ACPI_TABLES)
27 #include <arch/acpi.h>
28 #include <arch/acpigen.h>
30 #if CONFIG(GENERATE_SMBIOS_TABLES)
40 static u8 ipmi_revision_major
= 0x1;
41 static u8 ipmi_revision_minor
= 0x0;
43 static int ipmi_get_device_id(struct device
*dev
, struct ipmi_devid_rsp
*rsp
)
47 ret
= ipmi_kcs_message(dev
->path
.pnp
.port
, IPMI_NETFN_APPLICATION
, 0,
48 IPMI_BMC_GET_DEVICE_ID
, NULL
, 0, (u8
*)rsp
,
50 if (ret
< sizeof(struct ipmi_rsp
) || rsp
->resp
.completion_code
) {
51 printk(BIOS_ERR
, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
52 __func__
, ret
, rsp
->resp
.completion_code
);
55 if (ret
!= sizeof(*rsp
)) {
56 printk(BIOS_ERR
, "IPMI: %s response truncated\n", __func__
);
62 static int ipmi_get_bmc_self_test_result(struct device
*dev
, struct ipmi_selftest_rsp
*rsp
)
66 ret
= ipmi_kcs_message(dev
->path
.pnp
.port
, IPMI_NETFN_APPLICATION
, 0,
67 IPMI_BMC_GET_SELFTEST_RESULTS
, NULL
, 0, (u8
*)rsp
,
70 if (ret
< sizeof(struct ipmi_rsp
) || rsp
->resp
.completion_code
) {
71 printk(BIOS_ERR
, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
72 __func__
, ret
, rsp
->resp
.completion_code
);
75 if (ret
!= sizeof(*rsp
)) {
76 printk(BIOS_ERR
, "IPMI: %s response truncated\n", __func__
);
83 static void ipmi_kcs_init(struct device
*dev
)
85 struct ipmi_devid_rsp rsp
;
86 uint32_t man_id
= 0, prod_id
= 0;
87 struct drivers_ipmi_config
*conf
= NULL
;
88 struct ipmi_selftest_rsp selftestrsp
;
94 printk(BIOS_DEBUG
, "IPMI: PNP KCS 0x%x\n", dev
->path
.pnp
.port
);
97 conf
= dev
->chip_info
;
99 /* Get IPMI version for ACPI and SMBIOS */
100 if (conf
&& conf
->wait_for_bmc
&& conf
->bmc_boot_timeout
) {
102 stopwatch_init_msecs_expire(&sw
, conf
->bmc_boot_timeout
* 1000);
103 printk(BIOS_DEBUG
, "IPMI: Waiting for BMC...\n");
105 while (!stopwatch_expired(&sw
)) {
106 if (inb(dev
->path
.pnp
.port
) != 0xff)
110 if (stopwatch_expired(&sw
)) {
111 printk(BIOS_INFO
, "IPMI: Waiting for BMC timed out\n");
112 /* Don't write tables if communication failed */
118 printk(BIOS_INFO
, "Get BMC self test result...");
119 for (retry_count
= 0; retry_count
< conf
->bmc_boot_timeout
; retry_count
++) {
120 if (!ipmi_get_bmc_self_test_result(dev
, &selftestrsp
))
126 switch (selftestrsp
.result
) {
127 case IPMI_APP_SELFTEST_NO_ERROR
: /* 0x55 */
128 printk(BIOS_DEBUG
, "No Error\n");
130 case IPMI_APP_SELFTEST_NOT_IMPLEMENTED
: /* 0x56 */
131 printk(BIOS_DEBUG
, "Function Not Implemented\n");
133 case IPMI_APP_SELFTEST_ERROR
: /* 0x57 */
134 printk(BIOS_ERR
, "BMC: Corrupted or inaccessible data or device\n");
135 /* Don't write tables if communication failed */
138 case IPMI_APP_SELFTEST_FATAL_HW_ERROR
: /* 0x58 */
139 printk(BIOS_ERR
, "BMC: Fatal Hardware Error\n");
140 /* Don't write tables if communication failed */
143 case IPMI_APP_SELFTEST_RESERVED
: /* 0xFF */
144 printk(BIOS_DEBUG
, "Reserved\n");
147 default: /* Other Device Specific Hardware Error */
148 printk(BIOS_ERR
, "BMC: Device Specific Error\n");
149 /* Don't write tables if communication failed */
154 if (!ipmi_get_device_id(dev
, &rsp
)) {
155 /* Queried the IPMI revision from BMC */
156 ipmi_revision_minor
= IPMI_IPMI_VERSION_MINOR(rsp
.ipmi_version
);
157 ipmi_revision_major
= IPMI_IPMI_VERSION_MAJOR(rsp
.ipmi_version
);
159 memcpy(&man_id
, rsp
.manufacturer_id
,
160 sizeof(rsp
.manufacturer_id
));
162 memcpy(&prod_id
, rsp
.product_id
, sizeof(rsp
.product_id
));
164 printk(BIOS_INFO
, "IPMI: Found man_id 0x%06x, prod_id 0x%04x\n",
167 printk(BIOS_INFO
, "IPMI: Version %01x.%01x\n",
168 ipmi_revision_major
, ipmi_revision_minor
);
170 /* Don't write tables if communication failed */
175 #if CONFIG(HAVE_ACPI_TABLES)
176 static uint32_t uid_cnt
= 0;
179 ipmi_write_acpi_tables(struct device
*dev
, unsigned long current
,
180 struct acpi_rsdp
*rsdp
)
182 struct drivers_ipmi_config
*conf
= NULL
;
183 struct acpi_spmi
*spmi
;
184 s8 gpe_interrupt
= -1;
185 u32 apic_interrupt
= 0;
187 .space_id
= ACPI_ADDRESS_SPACE_IO
,
188 .access_size
= ACPI_ACCESS_SIZE_BYTE_ACCESS
,
189 .addrl
= dev
->path
.pnp
.port
,
193 switch (CONFIG_IPMI_KCS_REGISTER_SPACING
) {
195 addr
.bit_offset
= 32;
198 addr
.bit_offset
= 128;
201 printk(BIOS_ERR
, "IPMI: Unsupported register spacing for SPMI\n");
208 current
= ALIGN_UP(current
, 8);
209 printk(BIOS_DEBUG
, "ACPI: * SPMI at %lx\n", current
);
210 spmi
= (struct acpi_spmi
*)current
;
213 conf
= dev
->chip_info
;
217 gpe_interrupt
= conf
->gpe_interrupt
;
219 apic_interrupt
= conf
->apic_interrupt
;
222 /* Use command to get UID from ipmi_ssdt */
223 acpi_create_ipmi(dev
, spmi
, (ipmi_revision_major
<< 8) |
224 (ipmi_revision_minor
<< 4), &addr
,
225 IPMI_INTERFACE_KCS
, gpe_interrupt
, apic_interrupt
,
228 acpi_add_table(rsdp
, spmi
);
230 current
+= spmi
->header
.length
;
235 static void ipmi_ssdt(struct device
*dev
)
237 const char *scope
= acpi_device_scope(dev
);
238 struct drivers_ipmi_config
*conf
= NULL
;
241 printk(BIOS_ERR
, "IPMI: Missing ACPI scope for %s\n",
247 conf
= dev
->chip_info
;
249 /* Use command to pass UID to ipmi_write_acpi_tables */
250 dev
->command
= uid_cnt
++;
252 /* write SPMI device */
253 acpigen_write_scope(scope
);
254 acpigen_write_device("SPMI");
255 acpigen_write_name_string("_HID", "IPI0001");
256 acpigen_write_name_string("_STR", "IPMI_KCS");
257 acpigen_write_name_byte("_UID", dev
->command
);
258 acpigen_write_STA(0xf);
259 acpigen_write_name("_CRS");
260 acpigen_write_resourcetemplate_header();
261 acpigen_write_io16(dev
->path
.pnp
.port
, dev
->path
.pnp
.port
, 1, 1, 1);
262 acpigen_write_io16(dev
->path
.pnp
.port
+ CONFIG_IPMI_KCS_REGISTER_SPACING
,
263 dev
->path
.pnp
.port
+ CONFIG_IPMI_KCS_REGISTER_SPACING
, 1, 1, 1);
266 // FIXME: is that correct?
268 acpigen_write_irq(1 << conf
->apic_interrupt
);
271 acpigen_write_resourcetemplate_footer();
273 acpigen_write_method("_IFT", 0);
274 acpigen_write_return_byte(1); // KCS
277 acpigen_write_method("_SRV", 0);
278 acpigen_write_return_integer((ipmi_revision_major
<< 8) |
279 (ipmi_revision_minor
<< 4));
282 acpigen_pop_len(); /* pop device */
283 acpigen_pop_len(); /* pop scope */
287 #if CONFIG(GENERATE_SMBIOS_TABLES)
288 static int ipmi_smbios_data(struct device
*dev
, int *handle
,
289 unsigned long *current
)
291 struct drivers_ipmi_config
*conf
= NULL
;
292 u8 nv_storage
= 0xff;
299 conf
= dev
->chip_info
;
302 if (conf
->have_nv_storage
)
303 nv_storage
= conf
->nv_storage_device_address
;
304 i2c_address
= conf
->bmc_i2c_address
;
307 switch (CONFIG_IPMI_KCS_REGISTER_SPACING
) {
309 register_spacing
= 1 << 6;
312 register_spacing
= 2 << 6;
315 printk(BIOS_ERR
, "IPMI: Unsupported register spacing for SMBIOS\n");
318 register_spacing
= 0 << 6;
322 // add IPMI Device Information
323 len
+= smbios_write_type38(
325 SMBIOS_BMC_INTERFACE_KCS
,
326 ipmi_revision_minor
| (ipmi_revision_major
<< 4),
327 i2c_address
, // I2C address
328 nv_storage
, // NV storage
329 dev
->path
.pnp
.port
| 1, // IO interface
337 static void ipmi_set_resources(struct device
*dev
)
339 struct resource
*res
;
341 for (res
= dev
->resource_list
; res
; res
= res
->next
) {
342 if (!(res
->flags
& IORESOURCE_ASSIGNED
))
345 res
->flags
|= IORESOURCE_STORED
;
346 report_resource_stored(dev
, res
, "");
350 static void ipmi_read_resources(struct device
*dev
)
352 struct resource
*res
= new_resource(dev
, 0);
353 res
->base
= dev
->path
.pnp
.port
;
355 res
->flags
= IORESOURCE_IO
| IORESOURCE_ASSIGNED
| IORESOURCE_FIXED
;
358 static struct device_operations ops
= {
359 .read_resources
= ipmi_read_resources
,
360 .set_resources
= ipmi_set_resources
,
361 .enable_resources
= DEVICE_NOOP
,
362 .init
= ipmi_kcs_init
,
363 #if CONFIG(HAVE_ACPI_TABLES)
364 .write_acpi_tables
= ipmi_write_acpi_tables
,
365 .acpi_fill_ssdt_generator
= ipmi_ssdt
,
367 #if CONFIG(GENERATE_SMBIOS_TABLES)
368 .get_smbios_data
= ipmi_smbios_data
,
372 static void enable_dev(struct device
*dev
)
374 if (dev
->path
.type
!= DEVICE_PATH_PNP
)
375 printk(BIOS_ERR
, "%s: Unsupported device type\n",
377 else if (dev
->path
.pnp
.port
& 1)
378 printk(BIOS_ERR
, "%s: Base address needs to be aligned to 2\n",
384 struct chip_operations drivers_ipmi_ops
= {
385 CHIP_NAME("IPMI KCS")
386 .enable_dev
= enable_dev
,