summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/chromebook-x86/chromeos/power_management.c89
-rw-r--r--board/chromebook-x86/coreboot/coreboot.c18
-rw-r--r--drivers/video/cfb_console.c8
-rw-r--r--include/video.h1
-rw-r--r--lib/vbexport/display.c7
5 files changed, 114 insertions, 9 deletions
diff --git a/board/chromebook-x86/chromeos/power_management.c b/board/chromebook-x86/chromeos/power_management.c
index 8510c8e7b5..068eb18dea 100644
--- a/board/chromebook-x86/chromeos/power_management.c
+++ b/board/chromebook-x86/chromeos/power_management.c
@@ -12,6 +12,25 @@
#include <chromeos/power_management.h>
#include <common.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#define PM1_STS 0x00
+#define PWRBTN_STS (1 << 8)
+#define PM1_EN 0x02
+#define PM1_CNT 0x04
+#define SLP_EN (1 << 13)
+#define SLP_TYP (7 << 10)
+#define SLP_TYP_S0 (0 << 10)
+#define SLP_TYP_S1 (1 << 10)
+#define SLP_TYP_S3 (5 << 10)
+#define SLP_TYP_S4 (6 << 10)
+#define SLP_TYP_S5 (7 << 10)
+#define GPE0_EN 0x2c
+
+#define RST_CNT 0xcf9
+#define SYS_RST (1 << 1)
+#define RST_CPU (1 << 2)
int is_processor_reset(void)
{
@@ -19,14 +38,76 @@ int is_processor_reset(void)
return 1;
}
-/* This function never returns */
+/* Do a hard reset through the chipset's reset control register. This
+ * register is available on all x86 systems (at least those built in
+ * the last 10ys)
+ *
+ * This function never returns.
+ */
void cold_reboot(void)
{
- printf("cold_reboot used but not implemented.\n");
+ printf("Rebooting...\n");
+ outb(SYS_RST, RST_CNT);
+ outb(SYS_RST | RST_CPU, RST_CNT);
}
-/* This function never returns */
+/* Power down the machine by using the power management sleep control
+ * of the chipset. This will currently only work on Intel chipsets.
+ * However, adapting it to new chipsets is fairly simple. You will
+ * have to find the IO address of the power management register block
+ * in your southbridge, and look up the appropriate SLP_TYP_S5 value
+ * from your southbridge's data sheet.
+ *
+ * This function never returns.
+ */
void power_off(void)
{
- printf("power_off used but not implemented.\n");
+ u16 id, pmbase;
+ u32 reg32;
+
+ /* Make sure this is an Intel chipset with the
+ * LPC device hard coded at 0:1f.0
+ */
+ pci_read_config_word(PCI_BDF(0, 0x1f, 0), 0x00, &id);
+ if(id != 0x8086) {
+ printf("Power off is not implemented for this chipset. "
+ "Halting the CPU.\n");
+ for (;;)
+ asm("hlt");
+ }
+
+ /* Find the base address of the powermanagement registers */
+ pci_read_config_word(PCI_BDF(0, 0x1f, 0), 0x40, &pmbase);
+ pmbase &= 0xfffe;
+
+ /* Mask interrupts or system might stay in a coma
+ * (not executing code anymore, but not powered off either)
+ */
+ asm("cli");
+
+ /* Avoid any GPI waking the system from S5
+ * or the system might stay in a coma
+ */
+ outl(0x00000000, pmbase + GPE0_EN);
+
+ /* Clear Power Button Status */
+ outw(PWRBTN_STS, pmbase + PM1_STS);
+
+ /* PMBASE + 4, Bit 10-12, Sleeping Type,
+ * set to 111 -> S5, soft_off */
+
+ reg32 = inl(pmbase + PM1_CNT);
+
+ /* Set Sleeping Type to S5 (poweroff) */
+ reg32 &= ~(SLP_EN | SLP_TYP);
+ reg32 |= SLP_TYP_S5;
+ outl(reg32, pmbase + PM1_CNT);
+
+ /* Now set the Sleep Enable bit */
+ reg32 |= SLP_EN;
+ outl(reg32, pmbase + PM1_CNT);
+
+ for (;;)
+ asm("hlt");
}
+
diff --git a/board/chromebook-x86/coreboot/coreboot.c b/board/chromebook-x86/coreboot/coreboot.c
index 2ee0d86598..e660ddbca4 100644
--- a/board/chromebook-x86/coreboot/coreboot.c
+++ b/board/chromebook-x86/coreboot/coreboot.c
@@ -31,6 +31,7 @@
#include <netdev.h>
#include <asm/ic/coreboot/tables.h>
#include <asm/ic/coreboot/sysinfo.h>
+#include <chromeos/power_management.h>
#ifdef CONFIG_HW_WATCHDOG
#include <watchdog.h>
@@ -128,3 +129,20 @@ void hw_watchdog_reset(void)
{
}
#endif
+
+int do_coldboot(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ cold_reboot();
+ return (0);
+}
+
+U_BOOT_CMD(coldboot, 1, 1, do_coldboot, "Initiate a cold reboot.", "");
+
+int do_poweroff(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ power_off();
+ return (0);
+}
+
+U_BOOT_CMD(poweroff, 1, 1, do_poweroff, "Switch off power", "");
+
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index 6b0b766321..d79fa1efb1 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -1709,3 +1709,11 @@ int video_get_screen_columns (void)
return CONSOLE_COLS;
}
+int video_clear(void)
+{
+ memsetl(video_fb_address,
+ (VIDEO_VISIBLE_ROWS * VIDEO_LINE_LEN) / sizeof(int), 0);
+
+ return 0;
+}
+
diff --git a/include/video.h b/include/video.h
index 8b3799b0b0..a24035368c 100644
--- a/include/video.h
+++ b/include/video.h
@@ -21,5 +21,6 @@ int video_get_screen_rows (void);
int video_get_screen_columns (void);
int video_get_pixel_width (void);
int video_get_pixel_height(void);
+int video_clear(void);
#endif
diff --git a/lib/vbexport/display.c b/lib/vbexport/display.c
index cdf8862783..80f45128d9 100644
--- a/lib/vbexport/display.c
+++ b/lib/vbexport/display.c
@@ -55,6 +55,7 @@ static struct display_callbacks display_callbacks_ = {
.dc_position_cursor = video_position_cursor,
.dc_puts = video_puts,
.dc_display_bitmap = video_display_bitmap,
+ .dc_display_clear = video_clear
#endif
};
@@ -191,9 +192,5 @@ VbError_t VbExDisplayDebugInfo(const char *info_str)
/* this function is not technically part of the vboot interface */
int display_clear(void)
{
- if (display_callbacks_.dc_display_clear)
- return display_callbacks_.dc_display_clear();
-
- printf ("%s: not implemented!\n", __FUNCTION__);
- return -1;
+ return display_callbacks_.dc_display_clear();
}