diff --git a/src/drivers/pc80/Kconfig b/src/drivers/pc80/Kconfig index d9ff99151c..99e66d33e0 100644 --- a/src/drivers/pc80/Kconfig +++ b/src/drivers/pc80/Kconfig @@ -22,3 +22,18 @@ config LPC_TPM Enable this option to enable TPM support in coreboot. If unsure, say N. + +config DRIVERS_MC146818_RTC + bool + default y if ARCH_X86 + default n if !ARCH_X86 + +config DRIVERS_MC146818_CMOS + bool + default y if ARCH_X86 + default n if !ARCH_X86 + +config DRIVERS_RTC_HAS_ALTCENTURY + bool "The RTC supports alt century" + depends on DRIVERS_MC146818_RTC + default y diff --git a/src/drivers/pc80/Makefile.inc b/src/drivers/pc80/Makefile.inc index 9985433265..2b80d00f06 100644 --- a/src/drivers/pc80/Makefile.inc +++ b/src/drivers/pc80/Makefile.inc @@ -1,19 +1,26 @@ -ramstage-y += mc146818rtc.c +ramstage-$(CONFIG_DRIVERS_MC146818_RTC) += mc146818rtc.c +ramstage-$(CONFIG_DRIVERS_MC146818_CMOS) += mc146818.c ramstage-y += isa-dma.c ramstage-y += i8254.c ramstage-y += i8259.c ramstage-$(CONFIG_UDELAY_IO) += udelay_io.c ramstage-y += keyboard.c -romstage-$(CONFIG_LPC_TPM) += tpm.c +romstage-$(CONFIG_LPC_TPM) += tpm.c +ifeq ($(CONFIG_DRIVERS_MC146818_CMOS),y) romstage-$(CONFIG_USE_OPTION_TABLE) += mc146818rtc_early.c +endif + subdirs-y += vga cbfs-files-$(CONFIG_HAVE_CMOS_DEFAULT) += cmos.default cmos.default-file = $(CONFIG_CMOS_DEFAULT_FILE):nvramtool cmos.default-type = 0xaa +smm-y += mc146818.c smm-y += mc146818rtc.c $(obj)/drivers/pc80/mc146818rtc.ramstage.o : $(obj)/build.h +$(obj)/drivers/pc80/mc146818.ramstage.o : $(obj)/build.h $(obj)/drivers/pc80/mc146818rtc.smm.o : $(obj)/build.h +$(obj)/drivers/pc80/mc146818.smm.o : $(obj)/build.h diff --git a/src/drivers/pc80/mc146818.c b/src/drivers/pc80/mc146818.c new file mode 100644 index 0000000000..1500191509 --- /dev/null +++ b/src/drivers/pc80/mc146818.c @@ -0,0 +1,323 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#if CONFIG_USE_OPTION_TABLE +#include "option_table.h" +#include +#endif +#if CONFIG_HAVE_ACPI_RESUME +#include +#endif + + +static void cmos_reset_date(void) +{ + /* Now setup a default date equals to the build date */ + struct rtc_time time = { + .sec = 0, + .min = 0, + .hour = 1, + .mday = bcd2bin(COREBOOT_BUILD_DAY_BCD), + .mon = bcd2bin(COREBOOT_BUILD_MONTH_BCD), + .year = 2000 + bcd2bin(COREBOOT_BUILD_YEAR_BCD), + .wday = bcd2bin(COREBOOT_BUILD_WEEKDAY_BCD) + }; + rtc_set(&time); +} + +#if CONFIG_USE_OPTION_TABLE +static int cmos_checksum_valid(int range_start, int range_end, int cks_loc) +{ + int i; + u16 sum, old_sum; + sum = 0; + for (i = range_start; i <= range_end; i++) + sum += cmos_read(i); + old_sum = ((cmos_read(cks_loc) << 8) | cmos_read(cks_loc + 1)) & + 0x0ffff; + return sum == old_sum; +} + +static void cmos_set_checksum(int range_start, int range_end, int cks_loc) +{ + int i; + u16 sum; + sum = 0; + for (i = range_start; i <= range_end; i++) + sum += cmos_read(i); + cmos_write(((sum >> 8) & 0x0ff), cks_loc); + cmos_write(((sum >> 0) & 0x0ff), cks_loc + 1); +} +#endif + +#define RTC_CONTROL_DEFAULT (RTC_24H) +#define RTC_FREQ_SELECT_DEFAULT (RTC_REF_CLCK_32KHZ | RTC_RATE_1024HZ) + +#ifndef __SMM__ +void cmos_init(int invalid) +{ + int cmos_invalid = 0; + int checksum_invalid = 0; +#if CONFIG_USE_OPTION_TABLE + unsigned char x; +#endif + +#if CONFIG_HAVE_ACPI_RESUME + /* Avoid clearing pending interrupts and resetting the RTC control + * register in the resume path because the Linux kernel relies on + * this to know if it should restart the RTC timerqueue if the wake + * was due to the RTC alarm. + */ + if (acpi_slp_type == 3) + return; +#endif + + printk(BIOS_DEBUG, "RTC Init\n"); + +#if CONFIG_USE_OPTION_TABLE + /* See if there has been a CMOS power problem. */ + x = cmos_read(RTC_VALID); + cmos_invalid = !(x & RTC_VRT); + + /* See if there is a CMOS checksum error */ + checksum_invalid = !cmos_checksum_valid(PC_CKS_RANGE_START, + PC_CKS_RANGE_END,PC_CKS_LOC); + +#define CLEAR_CMOS 0 +#else +#define CLEAR_CMOS 1 +#endif + + if (invalid || cmos_invalid || checksum_invalid) { +#if CLEAR_CMOS + int i; + + cmos_write(0, 0x01); + cmos_write(0, 0x03); + cmos_write(0, 0x05); + for (i = 10; i < 128; i++) + cmos_write(0, i); +#endif + if (cmos_invalid) + cmos_reset_date(); + + printk(BIOS_WARNING, "RTC:%s%s%s%s\n", + invalid?" Clear requested":"", + cmos_invalid?" Power Problem":"", + checksum_invalid?" Checksum invalid":"", + CLEAR_CMOS?" zeroing cmos":""); + } + + /* Setup the real time clock */ + cmos_write(RTC_CONTROL_DEFAULT, RTC_CONTROL); + /* Setup the frequency it operates at */ + cmos_write(RTC_FREQ_SELECT_DEFAULT, RTC_FREQ_SELECT); + /* Ensure all reserved bits are 0 in register D */ + cmos_write(RTC_VRT, RTC_VALID); + +#if CONFIG_USE_OPTION_TABLE + /* See if there is a LB CMOS checksum error */ + checksum_invalid = !cmos_checksum_valid(LB_CKS_RANGE_START, + LB_CKS_RANGE_END,LB_CKS_LOC); + if (checksum_invalid) + printk(BIOS_DEBUG, "RTC: coreboot checksum invalid\n"); + + /* Make certain we have a valid checksum */ + cmos_set_checksum(PC_CKS_RANGE_START, PC_CKS_RANGE_END, PC_CKS_LOC); +#endif + + /* Clear any pending interrupts */ + cmos_read(RTC_INTR_FLAGS); +} +#endif + + +#if CONFIG_USE_OPTION_TABLE +/* + * This routine returns the value of the requested bits + * input bit = bit count from the beginning of the cmos image + * length = number of bits to include in the value + * vret = a character pointer to where the value is to be returned + * returns 0 = successful, -1 = an error occurred + */ +static int get_cmos_value(unsigned long bit, unsigned long length, void *vret) +{ + unsigned char *ret; + unsigned long byte,byte_bit; + unsigned long i; + unsigned char uchar; + + /* + * The table is checked when it is built to ensure all + * values are valid. + */ + 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 < 9) { /* one byte or less */ + uchar = cmos_read(byte); /* load the byte */ + uchar >>= byte_bit; /* shift the bits to byte align */ + /* clear unspecified bits */ + ret[0] = uchar & ((1 << length) - 1); + } else { /* more that one byte so transfer the whole bytes */ + for (i = 0; length; i++, length -= 8, byte++) { + /* load the byte */ + ret[i] = cmos_read(byte); + } + } + return 0; +} + +int get_option(void *dest, const char *name) +{ + 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_get_file_content(CBFS_DEFAULT_MEDIA, "cmos_layout.bin", + CBFS_COMPONENT_CMOS_LAYOUT); + if (!ct) { + printk(BIOS_ERR, "RTC: 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 (get_cmos_value(ce->bit, ce->length, dest)) + return -3; + if (!cmos_checksum_valid(LB_CKS_RANGE_START, LB_CKS_RANGE_END, + LB_CKS_LOC)) + 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 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) { + cmos_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_get_file_content(CBFS_DEFAULT_MEDIA, "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 */ + +/* + * If the CMOS is cleared, the rtc_reg has the invalid date. That + * hurts some OSes. Even if we don't set USE_OPTION_TABLE, we need + * to make sure the date is valid. + */ +void cmos_check_update_date(void) +{ + u8 year, century; + + /* Note: Need to check if the hardware supports RTC_CLK_ALTCENTURY. */ + century = CONFIG_DRIVERS_RTC_HAS_ALTCENTURY ? + cmos_read(RTC_CLK_ALTCENTURY) : 0; + year = cmos_read(RTC_CLK_YEAR); + + /* + * TODO: If century is 0xFF, 100% that the cmos is cleared. + * Other than that, so far rtc_year is the only entry to check + * if the date is valid. + */ + if (century > 0x99 || year > 0x99) /* Invalid date */ + cmos_reset_date(); +} diff --git a/src/drivers/pc80/mc146818rtc.c b/src/drivers/pc80/mc146818rtc.c index ae97379262..7954af41ba 100644 --- a/src/drivers/pc80/mc146818rtc.c +++ b/src/drivers/pc80/mc146818rtc.c @@ -1,325 +1,53 @@ -#include -#include -#include +/* + * This file is part of the coreboot project. + * + * Copyright 2014 The Chromium OS Authors. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include #include -#include -#include -#if CONFIG_USE_OPTION_TABLE -#include "option_table.h" -#include -#endif -#if CONFIG_HAVE_ACPI_RESUME -#include -#endif +#include - -static void cmos_update_date(u8 has_century) +int rtc_set(const struct rtc_time *time) { - /* Now setup a default date equals to the build date */ - cmos_write(0, RTC_CLK_SECOND); - cmos_write(0, RTC_CLK_MINUTE); - cmos_write(1, RTC_CLK_HOUR); - cmos_write(COREBOOT_BUILD_WEEKDAY_BCD + 1, RTC_CLK_DAYOFWEEK); - cmos_write(COREBOOT_BUILD_DAY_BCD, RTC_CLK_DAYOFMONTH); - cmos_write(COREBOOT_BUILD_MONTH_BCD, RTC_CLK_MONTH); - cmos_write(COREBOOT_BUILD_YEAR_BCD, RTC_CLK_YEAR); - if (has_century) cmos_write(0x20, RTC_CLK_ALTCENTURY); -} - -#if CONFIG_USE_OPTION_TABLE -static int cmos_checksum_valid(int range_start, int range_end, int cks_loc) -{ - int i; - u16 sum, old_sum; - sum = 0; - for (i = range_start; i <= range_end; i++) - sum += cmos_read(i); - old_sum = ((cmos_read(cks_loc) << 8) | cmos_read(cks_loc + 1)) & - 0x0ffff; - return sum == old_sum; -} - -static void cmos_set_checksum(int range_start, int range_end, int cks_loc) -{ - int i; - u16 sum; - sum = 0; - for (i = range_start; i <= range_end; i++) - sum += cmos_read(i); - cmos_write(((sum >> 8) & 0x0ff), cks_loc); - cmos_write(((sum >> 0) & 0x0ff), cks_loc + 1); -} -#endif - -#if CONFIG_ARCH_X86 -#define RTC_CONTROL_DEFAULT (RTC_24H) -#define RTC_FREQ_SELECT_DEFAULT (RTC_REF_CLCK_32KHZ | RTC_RATE_1024HZ) -#else -#if CONFIG_ARCH_ALPHA -#define RTC_CONTROL_DEFAULT (RTC_SQWE | RTC_24H) -#define RTC_FREQ_SELECT_DEFAULT (RTC_REF_CLCK_32KHZ | RTC_RATE_1024HZ) -#endif -#endif - -#ifndef __SMM__ -void cmos_init(int invalid) -{ - int cmos_invalid = 0; - int checksum_invalid = 0; -#if CONFIG_USE_OPTION_TABLE - unsigned char x; -#endif - -#if CONFIG_HAVE_ACPI_RESUME - /* Avoid clearing pending interrupts and resetting the RTC control - * register in the resume path because the Linux kernel relies on - * this to know if it should restart the RTC timerqueue if the wake - * was due to the RTC alarm. - */ - if (acpi_slp_type == 3) - return; -#endif - - printk(BIOS_DEBUG, "RTC Init\n"); - -#if CONFIG_USE_OPTION_TABLE - /* See if there has been a CMOS power problem. */ - x = cmos_read(RTC_VALID); - cmos_invalid = !(x & RTC_VRT); - - /* See if there is a CMOS checksum error */ - checksum_invalid = !cmos_checksum_valid(PC_CKS_RANGE_START, - PC_CKS_RANGE_END,PC_CKS_LOC); - -#define CLEAR_CMOS 0 -#else -#define CLEAR_CMOS 1 -#endif - - if (invalid || cmos_invalid || checksum_invalid) { -#if CLEAR_CMOS - int i; - - cmos_write(0, 0x01); - cmos_write(0, 0x03); - cmos_write(0, 0x05); - for (i = 10; i < 128; i++) - cmos_write(0, i); -#endif - if (cmos_invalid) - cmos_update_date(RTC_HAS_NO_ALTCENTURY); - - printk(BIOS_WARNING, "RTC:%s%s%s%s\n", - invalid?" Clear requested":"", - cmos_invalid?" Power Problem":"", - checksum_invalid?" Checksum invalid":"", - CLEAR_CMOS?" zeroing cmos":""); - } - - /* Setup the real time clock */ - cmos_write(RTC_CONTROL_DEFAULT, RTC_CONTROL); - /* Setup the frequency it operates at */ - cmos_write(RTC_FREQ_SELECT_DEFAULT, RTC_FREQ_SELECT); - /* Ensure all reserved bits are 0 in register D */ - cmos_write(RTC_VRT, RTC_VALID); - -#if CONFIG_USE_OPTION_TABLE - /* See if there is a LB CMOS checksum error */ - checksum_invalid = !cmos_checksum_valid(LB_CKS_RANGE_START, - LB_CKS_RANGE_END,LB_CKS_LOC); - if (checksum_invalid) - printk(BIOS_DEBUG, "RTC: coreboot checksum invalid\n"); - - /* Make certain we have a valid checksum */ - cmos_set_checksum(PC_CKS_RANGE_START, PC_CKS_RANGE_END, PC_CKS_LOC); -#endif - - /* Clear any pending interrupts */ - cmos_read(RTC_INTR_FLAGS); -} -#endif - - -#if CONFIG_USE_OPTION_TABLE -/* - * This routine returns the value of the requested bits. - * input bit = bit count from the beginning of the cmos image - * length = number of bits to include in the value - * vret = a character pointer to where the value is to be returned - * returns 0 = successful, -1 = an error occurred - */ -static int get_cmos_value(unsigned long bit, unsigned long length, void *vret) -{ - unsigned char *ret; - unsigned long byte,byte_bit; - unsigned long i; - unsigned char uchar; - - /* - * The table is checked when it is built to ensure all - * values are valid. - */ - 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 < 9) { /* one byte or less */ - uchar = cmos_read(byte); /* load the byte */ - uchar >>= byte_bit; /* shift the bits to byte align */ - /* clear unspecified bits */ - ret[0] = uchar & ((1 << length) - 1); - } else { /* more that one byte so transfer the whole bytes */ - for (i = 0; length; i++, length -= 8, byte++) { - /* load the byte */ - ret[i] = cmos_read(byte); - } - } + cmos_write(bin2bcd(time->sec), RTC_CLK_SECOND); + cmos_write(bin2bcd(time->min), RTC_CLK_MINUTE); + cmos_write(bin2bcd(time->hour), RTC_CLK_HOUR); + cmos_write(bin2bcd(time->mday), RTC_CLK_DAYOFMONTH); + cmos_write(bin2bcd(time->mon), RTC_CLK_MONTH); + cmos_write(bin2bcd(time->year % 100), RTC_CLK_YEAR); + if (CONFIG_DRIVERS_RTC_HAS_ALTCENTURY) + cmos_write(bin2bcd(time->year / 100), + RTC_CLK_ALTCENTURY); + cmos_write(bin2bcd(time->wday + 1), RTC_CLK_DAYOFWEEK); return 0; } -int get_option(void *dest, const char *name) +int rtc_get(struct rtc_time *time) { - 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_get_file_content(CBFS_DEFAULT_MEDIA, "cmos_layout.bin", - CBFS_COMPONENT_CMOS_LAYOUT); - if (!ct) { - printk(BIOS_ERR, "RTC: 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 (get_cmos_value(ce->bit, ce->length, dest)) - return -3; - if (!cmos_checksum_valid(LB_CKS_RANGE_START, LB_CKS_RANGE_END, - LB_CKS_LOC)) - 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 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) { - cmos_set_checksum(LB_CKS_RANGE_START, LB_CKS_RANGE_END, - LB_CKS_LOC); - } + time->sec = bcd2bin(cmos_read(RTC_CLK_SECOND)); + time->min = bcd2bin(cmos_read(RTC_CLK_MINUTE)); + time->hour = bcd2bin(cmos_read(RTC_CLK_HOUR)); + time->mday = bcd2bin(cmos_read(RTC_CLK_DAYOFMONTH)); + time->mon = bcd2bin(cmos_read(RTC_CLK_MONTH)); + time->year = bcd2bin(cmos_read(RTC_CLK_YEAR)); + if (CONFIG_DRIVERS_RTC_HAS_ALTCENTURY) + time->year += bcd2bin(cmos_read(RTC_CLK_ALTCENTURY)) * 100; + else + time->year += 2000; + time->wday = bcd2bin(cmos_read(RTC_CLK_DAYOFWEEK)) - 1; 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_get_file_content(CBFS_DEFAULT_MEDIA, "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 */ - -/* - * If the CMOS is cleared, the rtc_reg has the invalid date. That - * hurts some OSes. Even if we don't set USE_OPTION_TABLE, we need - * to make sure the date is valid. - */ -void cmos_check_update_date(u8 has_century) -{ - u8 year, century; - - /* Note: Need to check if the hardware supports RTC_CLK_ALTCENTURY. */ - century = has_century ? cmos_read(RTC_CLK_ALTCENTURY) : 0; - year = cmos_read(RTC_CLK_YEAR); - - /* - * TODO: If century is 0xFF, 100% that the cmos is cleared. - * Other than that, so far rtc_year is the only entry to check - * if the date is valid. - */ - if (century > 0x99 || year > 0x99) /* Invalid date */ - cmos_update_date(has_century); -} diff --git a/src/include/bcd.h b/src/include/bcd.h new file mode 100644 index 0000000000..a0850271b8 --- /dev/null +++ b/src/include/bcd.h @@ -0,0 +1,35 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2014 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + */ + +#ifndef _BCD_H_ +#define _BCD_H_ + +#include + +static inline uint8_t bcd2bin(uint8_t val) +{ + return ((val >> 4) & 0xf) * 10 + (val & 0xf); +} + +static inline uint8_t bin2bcd(uint8_t val) +{ + return ((val / 10) << 4) | (val % 10); +} + +#endif /* _BCD_H_ */ diff --git a/src/include/pc80/mc146818rtc.h b/src/include/pc80/mc146818rtc.h index 69841dd27a..549368a604 100644 --- a/src/include/pc80/mc146818rtc.h +++ b/src/include/pc80/mc146818rtc.h @@ -91,9 +91,6 @@ #define RTC_CLK_YEAR 9 #define RTC_CLK_ALTCENTURY 0x32 -#define RTC_HAS_ALTCENTURY 1 -#define RTC_HAS_NO_ALTCENTURY 0 - /* On PCs, the checksum is built only over bytes 16..45 */ #define PC_CKS_RANGE_START 16 #define PC_CKS_RANGE_END 45 @@ -171,7 +168,7 @@ static inline void cmos_write32(u8 offset, u32 value) #if !defined(__ROMCC__) void cmos_init(int invalid); -void cmos_check_update_date(u8 has_century); +void cmos_check_update_date(void); #if CONFIG_USE_OPTION_TABLE int set_option(const char *name, void *val); int get_option(void *dest, const char *name); diff --git a/src/include/rtc.h b/src/include/rtc.h new file mode 100644 index 0000000000..ba9a9c351d --- /dev/null +++ b/src/include/rtc.h @@ -0,0 +1,37 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2014 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + */ + +#ifndef _RTC_H_ +#define _RTC_H_ + +struct rtc_time +{ + int sec; + int min; + int hour; + int mday; + int mon; + int year; + int wday; +}; + +int rtc_set(const struct rtc_time *time); +int rtc_get(struct rtc_time *time); + +#endif /* _RTC_H_ */ diff --git a/src/southbridge/amd/agesa/hudson/lpc.c b/src/southbridge/amd/agesa/hudson/lpc.c index b2f37bd132..4a504cd5b8 100644 --- a/src/southbridge/amd/agesa/hudson/lpc.c +++ b/src/southbridge/amd/agesa/hudson/lpc.c @@ -68,7 +68,7 @@ static void lpc_init(device_t dev) byte |= 1 << 0 | 1 << 3; pci_write_config8(dev, 0xBB, byte); - cmos_check_update_date(RTC_HAS_ALTCENTURY); + cmos_check_update_date(); /* Initialize the real time clock. * The 0 argument tells cmos_init not to diff --git a/src/southbridge/amd/cimx/sb700/late.c b/src/southbridge/amd/cimx/sb700/late.c index bbb6242c63..7b9cf61ad1 100644 --- a/src/southbridge/amd/cimx/sb700/late.c +++ b/src/southbridge/amd/cimx/sb700/late.c @@ -77,7 +77,7 @@ static void lpc_init(device_t dev) { printk(BIOS_DEBUG, "SB700 - Late.c - lpc_init - Start.\n"); - cmos_check_update_date(RTC_HAS_ALTCENTURY); + cmos_check_update_date(); /* Initialize the real time clock. * The 0 argument tells cmos_init not to diff --git a/src/southbridge/amd/cimx/sb800/late.c b/src/southbridge/amd/cimx/sb800/late.c index 68fa5e553a..bf1c71f2cd 100644 --- a/src/southbridge/amd/cimx/sb800/late.c +++ b/src/southbridge/amd/cimx/sb800/late.c @@ -126,7 +126,7 @@ static void lpc_init(device_t dev) { printk(BIOS_DEBUG, "SB800 - Late.c - lpc_init - Start.\n"); - cmos_check_update_date(RTC_HAS_ALTCENTURY); + cmos_check_update_date(); /* Initialize the real time clock. * The 0 argument tells cmos_init not to diff --git a/src/southbridge/amd/cimx/sb900/late.c b/src/southbridge/amd/cimx/sb900/late.c index 5b78490db9..1951ad5807 100644 --- a/src/southbridge/amd/cimx/sb900/late.c +++ b/src/southbridge/amd/cimx/sb900/late.c @@ -99,7 +99,7 @@ static void lpc_init(device_t dev) printk(BIOS_DEBUG, "SB900 - Late.c - lpc_init - Start.\n"); /* SB Configure HPET base and enable bit */ //- hpetInit(sb_config, &(sb_config->BuildParameters)); - cmos_check_update_date(RTC_HAS_ALTCENTURY); + cmos_check_update_date(); /* Initialize the real time clock. * The 0 argument tells cmos_init not to diff --git a/src/southbridge/amd/sb600/lpc.c b/src/southbridge/amd/sb600/lpc.c index 517ab59af3..fc96b83a94 100644 --- a/src/southbridge/amd/sb600/lpc.c +++ b/src/southbridge/amd/sb600/lpc.c @@ -59,7 +59,7 @@ static void lpc_init(device_t dev) byte &= ~(1 << 1); pci_write_config8(dev, 0x78, byte); - cmos_check_update_date(RTC_HAS_ALTCENTURY); + cmos_check_update_date(); } static void sb600_lpc_read_resources(device_t dev) diff --git a/src/southbridge/amd/sb700/lpc.c b/src/southbridge/amd/sb700/lpc.c index 2a1ffa8f69..54181fdbdc 100644 --- a/src/southbridge/amd/sb700/lpc.c +++ b/src/southbridge/amd/sb700/lpc.c @@ -81,7 +81,7 @@ static void lpc_init(device_t dev) } #endif - cmos_check_update_date(RTC_HAS_ALTCENTURY); + cmos_check_update_date(); } void set_cbmem_toc(struct cbmem_entry *toc) diff --git a/src/southbridge/amd/sb800/lpc.c b/src/southbridge/amd/sb800/lpc.c index 7a4dd831da..989139f125 100644 --- a/src/southbridge/amd/sb800/lpc.c +++ b/src/southbridge/amd/sb800/lpc.c @@ -67,7 +67,7 @@ static void lpc_init(device_t dev) byte |= 1 << 0 | 1 << 3; pci_write_config8(dev, 0xBB, byte); - cmos_check_update_date(RTC_HAS_ALTCENTURY); + cmos_check_update_date(); } static void sb800_lpc_read_resources(device_t dev)