mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-31 12:08:19 +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>
		
			
				
	
	
		
			140 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			140 lines
		
	
	
		
			3.0 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));
 |