CMOS: add set_option()

Change-Id: I584189d9fcf7c9b831d9c020ee7ed59bb5ae08e8
Signed-off-by: Sven Schnelle <svens@stackframe.org>
Reviewed-on: http://review.coreboot.org/23
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <patrick@georgi-clan.de>
This commit is contained in:
Sven Schnelle 2011-06-06 15:58:54 +02:00 committed by Patrick Georgi
parent d40d4f7712
commit d29e5bb933
2 changed files with 85 additions and 0 deletions

View File

@ -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
static inline 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)

View File

@ -252,4 +252,87 @@ 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 >= LB_CKS_RANGE_START && byte <= LB_CKS_RANGE_END)
chksum_update_needed = 1;
} else { /* more that one byte so transfer the whole bytes */
if (byte_bit || length % 8)
return -1;
for(i=0; length; i++, length-=8, byte++)
cmos_write(ret[i], byte);
if (byte >= LB_CKS_RANGE_START && byte <= LB_CKS_RANGE_END)
chksum_update_needed = 1;
}
if (chksum_update_needed) {
rtc_set_checksum(LB_CKS_RANGE_START,
LB_CKS_RANGE_END,LB_CKS_LOC);
}
return 0;
}
int set_option(const char *name, void *value)
{
struct cmos_option_table *ct;
struct cmos_entries *ce;
unsigned long length;
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);
}
length = ce->length;
if (ce->config == 's') {
length = MAX(strlen((const char *)value) * 8, ce->length - 8);
/* make sure the string is null terminated */
if ((set_cmos_value(ce->bit + ce->length - 8, 8, &(u8[]){0})))
return (-3);
}
if ((set_cmos_value(ce->bit, length, value)))
return (-3);
return 0;
}
#endif /* CONFIG_USE_OPTION_TABLE */