mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-27 07:51:38 +00:00

Coreboot tables provide information about the CMOS-RAM checksum. Add a command which can check and update this. With this it is possible to adjust CMOS-RAM settings and tidy up the checksum afterwards. Signed-off-by: Simon Glass <sjg@chromium.org>
139 lines
3 KiB
C
139 lines
3 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Support for booting from coreboot
|
|
*
|
|
* Copyright 2021 Google LLC
|
|
*/
|
|
|
|
#define LOG_CATEGORY UCLASS_RTC
|
|
|
|
#include <command.h>
|
|
#include <dm.h>
|
|
#include <rtc.h>
|
|
#include <asm/cb_sysinfo.h>
|
|
#include <asm/global_data.h>
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
const struct sysinfo_t *get_table(void)
|
|
{
|
|
if (!gd->arch.coreboot_table) {
|
|
printf("No coreboot sysinfo table found\n");
|
|
return NULL;
|
|
}
|
|
|
|
return &lib_sysinfo;
|
|
}
|
|
|
|
static int calc_sum(struct udevice *dev, uint start_bit, uint bit_count)
|
|
{
|
|
uint start_byte = start_bit / 8;
|
|
uint byte_count = bit_count / 8;
|
|
int ret, i;
|
|
uint sum;
|
|
|
|
log_debug("Calc sum from %x: %x bytes\n", start_byte, byte_count);
|
|
sum = 0;
|
|
for (i = 0; i < bit_count / 8; i++) {
|
|
ret = rtc_read8(dev, start_bit / 8 + i);
|
|
if (ret < 0)
|
|
return ret;
|
|
sum += ret;
|
|
}
|
|
|
|
return (sum & 0xff) << 8 | (sum & 0xff00) >> 8;
|
|
}
|
|
|
|
/**
|
|
* prep_cbcmos() - Prepare for a CMOS-RAM command
|
|
*
|
|
* @tab: coreboot table
|
|
* @devnum: RTC device name to use, or NULL for the first one
|
|
* @dep: Returns RTC device on success
|
|
* Return: calculated checksum for CMOS RAM or -ve on error
|
|
*/
|
|
static int prep_cbcmos(const struct sysinfo_t *tab, const char *devname,
|
|
struct udevice **devp)
|
|
{
|
|
struct udevice *dev;
|
|
int ret;
|
|
|
|
if (!tab)
|
|
return CMD_RET_FAILURE;
|
|
if (devname)
|
|
ret = uclass_get_device_by_name(UCLASS_RTC, devname, &dev);
|
|
else
|
|
ret = uclass_first_device_err(UCLASS_RTC, &dev);
|
|
if (ret) {
|
|
printf("Failed to get RTC device: %dE\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = calc_sum(dev, tab->cmos_range_start,
|
|
tab->cmos_range_end + 1 - tab->cmos_range_start);
|
|
if (ret < 0) {
|
|
printf("Failed to read RTC device: %dE\n", ret);
|
|
return ret;
|
|
}
|
|
*devp = dev;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int do_cbcmos_check(struct cmd_tbl *cmdtp, int flag, int argc,
|
|
char *const argv[])
|
|
{
|
|
const struct sysinfo_t *tab = get_table();
|
|
struct udevice *dev;
|
|
u16 cur, sum;
|
|
int ret;
|
|
|
|
ret = prep_cbcmos(tab, argv[1], &dev);
|
|
if (ret < 0)
|
|
return CMD_RET_FAILURE;
|
|
sum = ret;
|
|
|
|
ret = rtc_read16(dev, tab->cmos_checksum_location / 8, &cur);
|
|
if (ret < 0) {
|
|
printf("Failed to read RTC device: %dE\n", ret);
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
if (sum != cur) {
|
|
printf("Checksum %04x error: calculated %04x\n", cur, sum);
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int do_cbcmos_update(struct cmd_tbl *cmdtp, int flag, int argc,
|
|
char *const argv[])
|
|
{
|
|
const struct sysinfo_t *tab = get_table();
|
|
struct udevice *dev;
|
|
u16 sum;
|
|
int ret;
|
|
|
|
ret = prep_cbcmos(tab, argv[1], &dev);
|
|
if (ret < 0)
|
|
return CMD_RET_FAILURE;
|
|
sum = ret;
|
|
|
|
ret = rtc_write16(dev, tab->cmos_checksum_location / 8, sum);
|
|
if (ret < 0) {
|
|
printf("Failed to read RTC device: %dE\n", ret);
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
printf("Checksum %04x written\n", sum);
|
|
|
|
return 0;
|
|
}
|
|
|
|
U_BOOT_LONGHELP(cbcmos,
|
|
"check - check CMOS RAM\n"
|
|
"cbcmos update - Update CMOS-RAM checksum";
|
|
);
|
|
|
|
U_BOOT_CMD_WITH_SUBCMDS(cbcmos, "coreboot CMOS RAM", cbcmos_help_text,
|
|
U_BOOT_SUBCMD_MKENT(check, 2, 1, do_cbcmos_check),
|
|
U_BOOT_SUBCMD_MKENT(update, 2, 1, do_cbcmos_update));
|