mb/ocp/monolake: Add IPMI CMOS clear support

coreboot would clear CMOS by request via IPMI command, for example
BMC can issue "bios-util server --boot_order enable --clear_CMOS"
to set the request and reboot the system, then coreboot would clear CMOS
on the next boot.

Tested on Mono Lake

Change-Id: I21d44557896680cfac3c3b6d83e07b755b242cad
Signed-off-by: Johnny Lin <johnny_lin@wiwynn.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/34857
Reviewed-by: Johnny Lin
Reviewed-by: Andrey Petrov <andrey.petrov@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Johnny Lin 2019-08-13 15:36:23 +08:00 committed by Andrey Petrov
parent a4542990f4
commit 64d8b9decf
5 changed files with 150 additions and 0 deletions

View File

@ -12,6 +12,7 @@ config BOARD_SPECIFIC_OPTIONS
select MAINBOARD_USES_IFD_GBE_REGION
select MAINBOARD_HAS_LPC_TPM
select MAINBOARD_HAS_TPM1
select IPMI_KCS
config INTEGRATED_UART
def_bool n
@ -47,4 +48,7 @@ config FMDFILE
string
default "src/mainboard/$(CONFIG_MAINBOARD_DIR)/board.fmd"
config IPMI_KCS_REGISTER_SPACING
default 4
endif # BOARD_OCP_MONOLAKE

View File

@ -14,3 +14,4 @@
##
ramstage-y += irqroute.c
ramstage-y += ipmi.c

View File

@ -0,0 +1,80 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2019 Wiwynn Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdint.h>
#include <drivers/ipmi/ipmi_kcs.h>
#include <console/console.h>
#include "ipmi.h"
#define BMC_KCS_BASE 0xca2
int is_ipmi_clear_cmos_set(ipmi_oem_rsp_t *rsp)
{
int ret;
ipmi_oem_req_t req;
if (rsp == NULL) {
printk(BIOS_ERR, "%s failed, null pointer parameter\n",
__func__);
return 0;
}
/* IPMI OEM get bios boot order command to check if the valid bit and
the CMOS clear bit are both set from the response BootMode byte. */
ret = ipmi_kcs_message(BMC_KCS_BASE, IPMI_NETFN_OEM, 0x0,
IPMI_OEM_GET_BIOS_BOOT_ORDER,
(const unsigned char *) &req, sizeof(ipmi_oem_req_t),
(unsigned char *) rsp, sizeof(ipmi_oem_rsp_t));
if (ret < sizeof(struct ipmi_rsp) || rsp->CompletionCode) {
printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
__func__, ret, rsp->CompletionCode);
return 0;
}
if (GET_VALID_BIT(rsp->Data.BootMode) && GET_CMOS_BIT(rsp->Data.BootMode)) {
printk(BIOS_INFO, "IPMI CMOS clear requested\n");
return 1;
}
printk(BIOS_DEBUG, "IPMI CMOS clear is not set\n");
return 0;
}
void clear_ipmi_flags(ipmi_oem_rsp_t *rsp_get)
{
int ret;
ipmi_oem_req_t req;
struct ipmi_rsp rsp;
if (rsp_get == NULL) {
printk(BIOS_ERR, "%s failed, null pointer parameter\n",
__func__);
return;
}
req = rsp_get->Data;
CLEAR_CMOS_AND_VALID_BIT(req.BootMode);
ret = ipmi_kcs_message(BMC_KCS_BASE, IPMI_NETFN_OEM, 0x0,
IPMI_OEM_SET_BIOS_BOOT_ORDER,
(const unsigned char *) &req, sizeof(ipmi_oem_req_t),
(unsigned char *) &rsp, sizeof(rsp));
if (ret < sizeof(struct ipmi_rsp) || rsp.completion_code) {
printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
__func__, ret, rsp.completion_code);
return;
}
printk(BIOS_INFO, "clear IPMI flags done\n");
}

View File

@ -0,0 +1,53 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2019 Wiwynn Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef MONOLAKE_IPMI_H
#define MONOLAKE_IPMI_H
#include <types.h>
#define IPMI_NETFN_OEM 0x30
#define IPMI_OEM_SET_BIOS_BOOT_ORDER 0x52
#define IPMI_OEM_GET_BIOS_BOOT_ORDER 0x53
#define GET_CMOS_BIT(x) ((x) & (1 << 1))
#define GET_VALID_BIT(x) ((x) & (1 << 7))
#define CLEAR_CMOS_AND_VALID_BIT(x) ((x) &= 0x7d)
typedef struct {
u8 BootMode; /* Bit 1:CMOS clear, bit 7:valid bit. */
u8 Boot0000;
u8 Boot0001;
u8 Boot0002;
u8 Boot0003;
u8 Boot0004;
} __packed ipmi_oem_req_t;
typedef struct {
u16 KcsRsp;
u8 CompletionCode;
ipmi_oem_req_t Data;
} __packed ipmi_oem_rsp_t;
/*
* IPMI get response to check if valid and CMOS clear bit
* are both set and store the IPMI response data to the parameter.
*/
int is_ipmi_clear_cmos_set(ipmi_oem_rsp_t *rsp);
/*
* Clear valid bit and CMOS clear bit from the parameter
* and set it back via IPMI.
*/
void clear_ipmi_flags(ipmi_oem_rsp_t *rsp);
#endif

View File

@ -19,6 +19,9 @@
#if CONFIG(VGA_ROM_RUN)
#include <x86emu/x86emu.h>
#endif
#include <pc80/mc146818rtc.h>
#include <cf9_reset.h>
#include "ipmi.h"
#define BMC_KCS_BASE 0xca2
#define INTERFACE_IS_IO 0x1
@ -57,9 +60,18 @@ static void mainboard_enable(struct device *dev)
/* Enable access to the BMC IPMI via KCS */
struct device *lpc_sio_dev = dev_find_slot_pnp(BMC_KCS_BASE, 0);
struct resource *res = new_resource(lpc_sio_dev, BMC_KCS_BASE);
ipmi_oem_rsp_t rsp;
res->base = BMC_KCS_BASE;
res->size = 1;
res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
if (is_ipmi_clear_cmos_set(&rsp)) {
/* TODO: Should also try to restore CMOS to cmos.default
* if USE_OPTION_TABLE is set */
cmos_init(1);
clear_ipmi_flags(&rsp);
system_reset();
}
}
struct chip_operations mainboard_ops = {