// SPDX-License-Identifier: GPL-2.0+ /* * Support for booting from coreboot * * Copyright 2021 Google LLC */ #define LOG_CATEGORY UCLASS_RTC #include #include #include #include #include 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));