--- /dev/null
+// 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));
*/
#include <command.h>
+#include <dm.h>
+#include <rtc.h>
#include <test/cmd.h>
#include <test/test.h>
#include <test/ut.h>
+enum {
+ CSUM_LOC = 0x3f0 / 8,
+};
+
/**
* test_cmd_cbsysinfo() - test the cbsysinfo command produces expected output
*
return 0;
}
CMD_TEST(test_cmd_cbsysinfo, UTF_CONSOLE);
+
+/* test cbcmos command */
+static int test_cmd_cbcmos(struct unit_test_state *uts)
+{
+ u16 old_csum, new_csum;
+ struct udevice *dev;
+
+ /* initially the checksum should be correct */
+ ut_assertok(run_command("cbcmos check", 0));
+ ut_assert_console_end();
+
+ /* make a change to the checksum */
+ ut_assertok(uclass_first_device_err(UCLASS_RTC, &dev));
+ ut_assertok(rtc_read16(dev, CSUM_LOC, &old_csum));
+ ut_assertok(rtc_write16(dev, CSUM_LOC, old_csum + 1));
+
+ /* now the command should fail */
+ ut_asserteq(1, run_command("cbcmos check", 0));
+ ut_assert_nextline("Checksum %04x error: calculated %04x",
+ old_csum + 1, old_csum);
+ ut_assert_console_end();
+
+ /* now get it to fix the checksum */
+ ut_assertok(run_command("cbcmos update", 0));
+ ut_assert_nextline("Checksum %04x written", old_csum);
+ ut_assert_console_end();
+
+ /* check the RTC looks right */
+ ut_assertok(rtc_read16(dev, CSUM_LOC, &new_csum));
+ ut_asserteq(old_csum, new_csum);
+ ut_assert_console_end();
+
+ return 0;
+}
+CMD_TEST(test_cmd_cbcmos, UTF_CONSOLE);