Patchwork New patch to review: 46cc5bc CMOS: add set_option()

login
register
about
Submitter gerrit@coreboot.org
Date 2011-06-12 10:15:21
Message ID <E1QVhhR-0005O0-AX@ra.coresystems.de>
Download mbox | patch
Permalink /patch/3113/
State New, archived
Headers show

Comments

gerrit@coreboot.org - 2011-06-12 10:15:21
Sven Schnelle (svens@stackframe.org) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/23

-gerrit

Patch

commit 46cc5bc80381e9ef4d1bde0a02e0e0e953f6900f
Author: Sven Schnelle <svens@stackframe.org>
Date:   Mon Jun 6 15:58:54 2011 +0200

    CMOS: add set_option()
    
    Change-Id: I584189d9fcf7c9b831d9c020ee7ed59bb5ae08e8
    Signed-off-by: Sven Schnelle <svens@stackframe.org>

diff --git a/src/include/pc80/mc146818rtc.h b/src/include/pc80/mc146818rtc.h
index 7be552d..fda437f 100644
--- a/src/include/pc80/mc146818rtc.h
+++ b/src/include/pc80/mc146818rtc.h
@@ -109,9 +109,11 @@  static inline void cmos_write(unsigned char val, unsigned char addr)
 #if !defined(__ROMCC__)
 void rtc_init(int invalid);
 #if CONFIG_USE_OPTION_TABLE
+int set_option(const char *name, void *val);
 int get_option(void *dest, const char *name);
 unsigned read_option_lowlevel(unsigned start, unsigned size, unsigned def);
 #else
+int set_option(const char *name __attribute__((unused)), void *val __attribute__((unused))) { return -2; };
 static inline int get_option(void *dest __attribute__((unused)),
 	const char *name __attribute__((unused))) { return -2; }
 static inline unsigned read_option_lowlevel(unsigned start, unsigned size, unsigned def)
diff --git a/src/pc80/mc146818rtc.c b/src/pc80/mc146818rtc.c
index 5850ec6..50543d2 100644
--- a/src/pc80/mc146818rtc.c
+++ b/src/pc80/mc146818rtc.c
@@ -252,4 +252,74 @@  int get_option(void *dest, const char *name)
 		return(-4);
 	return(0);
 }
+
+static int set_cmos_value(unsigned long bit, unsigned long length, void *vret)
+{
+	unsigned char *ret;
+	unsigned long byte,byte_bit;
+	unsigned long i;
+	unsigned char uchar, mask;
+	unsigned int chksum_update_needed = 0;
+
+	ret = vret;
+	byte = bit / 8;			/* find the byte where the data starts */
+	byte_bit = bit % 8;		/* find the bit in the byte where the data starts */
+	if(length <= 8) {		/* one byte or less */
+		mask = (1 << length) - 1;
+		mask <<= byte_bit;
+
+		uchar = cmos_read(byte);
+		uchar &= ~mask;
+		uchar |= (ret[0] << byte_bit);
+		cmos_write(uchar, byte);
+		if (byte >= PC_CKS_RANGE_START && byte <= PC_CKS_RANGE_END)
+			chksum_update_needed = 1;
+	} else {			/* more that one byte so transfer the whole bytes */
+		for(i=0; length; i++, length-=8, byte++)
+			cmos_write(ret[i], byte);
+			if (byte >= PC_CKS_RANGE_START && byte <= PC_CKS_RANGE_END)
+				chksum_update_needed = 1;
+	}
+
+	if (chksum_update_needed) {
+		rtc_set_checksum(PC_CKS_RANGE_START,
+			PC_CKS_RANGE_END,PC_CKS_LOC);
+	}
+	return 0;
+}
+
+
+int set_option(const char *name, void *value)
+{
+	struct cmos_option_table *ct;
+	struct cmos_entries *ce;
+	size_t namelen;
+	int found=0;
+
+	/* Figure out how long name is */
+	namelen = strnlen(name, CMOS_MAX_NAME_LENGTH);
+
+	/* find the requested entry record */
+	ct=cbfs_find_file("cmos_layout.bin", CBFS_COMPONENT_CMOS_LAYOUT);
+	if (!ct) {
+		printk(BIOS_ERR, "cmos_layout.bin could not be found. Options are disabled\n");
+		return(-2);
+	}
+	ce=(struct cmos_entries*)((unsigned char *)ct + ct->header_length);
+	for(;ce->tag==LB_TAG_OPTION;
+		ce=(struct cmos_entries*)((unsigned char *)ce + ce->size)) {
+		if (memcmp(ce->name, name, namelen) == 0) {
+			found=1;
+			break;
+		}
+	}
+	if(!found) {
+		printk(BIOS_DEBUG, "WARNING: No CMOS option '%s'.\n", name);
+		return(-2);
+	}
+
+	if(set_cmos_value(ce->bit, ce->length, value))
+		return(-3);
+	return(0);
+}
 #endif /* CONFIG_USE_OPTION_TABLE */