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:
parent
a4542990f4
commit
64d8b9decf
|
@ -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
|
||||
|
|
|
@ -14,3 +14,4 @@
|
|||
##
|
||||
|
||||
ramstage-y += irqroute.c
|
||||
ramstage-y += ipmi.c
|
||||
|
|
|
@ -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");
|
||||
}
|
|
@ -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
|
|
@ -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 = {
|
||||
|
|
Loading…
Reference in New Issue