From e9328ac4f63351b4282916034270aa86b7e74922 Mon Sep 17 00:00:00 2001 From: Randall Spangler Date: Fri, 6 Apr 2012 09:33:41 -0700 Subject: Support dynamically changing the system clock Add nopll command to turn off the PLL, reducing the system clock to 16Mhz. Signed-off-by: Randall Spangler BUG=chrome-os-partner:8798 TEST=manual boot system press power button to boot x86 temps // should print all temperatures timerinfo timerinfo timerinfo // convince yourself this is counting up at about 1MHz nopll // this drops the system clock to 16MHz temps // should still print all temperatures timerinfo timerinfo timerinfo // should still be counting up at about 1MHz Change-Id: Ie29ceb17af348148bffadf63d60c1b731f4c3f6d --- board/bds/board.h | 3 - board/link/board.h | 3 - chip/lm4/clock.c | 164 ++++++++++++++++++++++++++++++++------------------ chip/lm4/hwtimer.c | 20 +++--- chip/lm4/i2c.c | 37 +++++++----- chip/lm4/peci.c | 42 ++++++++----- chip/lm4/registers.h | 10 +++ chip/lm4/watchdog.c | 24 +++++--- chip/stm32l/clock.c | 13 ---- core/cortex-m/task.c | 13 +++- core/cortex-m/timer.c | 3 +- include/clock.h | 19 ++++-- include/hwtimer.h | 3 + include/i2c.h | 5 +- include/peci.h | 3 + include/watchdog.h | 20 +++--- test/powerdemo.c | 6 +- 17 files changed, 243 insertions(+), 145 deletions(-) diff --git a/board/bds/board.h b/board/bds/board.h index 67aad5f401..152b8ee182 100644 --- a/board/bds/board.h +++ b/board/bds/board.h @@ -11,9 +11,6 @@ /* Config flags */ #define CONFIG_LIGHTBAR -/* 66.667 Mhz clock frequency */ -#define CPU_CLOCK 66666667 - /* Fan PWM channels */ #define FAN_CH_KBLIGHT 1 /* Keyboard backlight */ #define FAN_CH_POWER_LED 3 /* Power adapter LED */ diff --git a/board/link/board.h b/board/link/board.h index b0228961b7..ccc803c68d 100644 --- a/board/link/board.h +++ b/board/link/board.h @@ -21,9 +21,6 @@ #define CONFIG_TMP006 #define CONFIG_USB_CHARGE -/* 66.667 Mhz clock frequency */ -#define CPU_CLOCK 66666667 - /* Fan PWM channels */ #define FAN_CH_CPU 0 /* CPU fan */ #define FAN_CH_KBLIGHT 1 /* Keyboard backlight */ diff --git a/chip/lm4/clock.c b/chip/lm4/clock.c index c80f36ecc1..694f1bc1b9 100644 --- a/chip/lm4/clock.c +++ b/chip/lm4/clock.c @@ -5,41 +5,74 @@ /* Clocks and power management settings */ -#include - #include "board.h" #include "clock.h" #include "config.h" #include "console.h" #include "gpio.h" +#include "registers.h" +#include "system.h" #include "task.h" #include "timer.h" #include "uart.h" -#include "registers.h" #include "util.h" -/** - * Idle task - * executed when no task are ready to be scheduled - */ -void __idle(void) +#define PLL_CLOCK 66666667 /* System clock = 200MHz PLL/3 = 66.667MHz */ + +/* Disable the PLL; run off internal oscillator. */ +static void clock_disable_pll(void) { - while (1) { - /* wait for the irq event */ - asm("wfi"); - /* TODO more power management here */ - } + /* Switch to 16MHz internal oscillator and power down the PLL */ + LM4_SYSTEM_RCC = LM4_SYSTEM_RCC_SYSDIV(0) | + LM4_SYSTEM_RCC_BYPASS | + LM4_SYSTEM_RCC_PWRDN | + LM4_SYSTEM_RCC_OSCSRC(1) | + LM4_SYSTEM_RCC_MOSCDIS; + LM4_SYSTEM_RCC2 &= ~LM4_SYSTEM_RCC2_USERCC2; +} + + +/* Enable the PLL to run at full clock speed */ +static void clock_enable_pll(void) +{ + /* Disable the PLL so we can reconfigure it */ + clock_disable_pll(); + + /* Enable the PLL (PWRDN is no longer set) and set divider. PLL is + * still bypassed, since it hasn't locked yet. */ + LM4_SYSTEM_RCC = LM4_SYSTEM_RCC_SYSDIV(2) | + LM4_SYSTEM_RCC_USESYSDIV | + LM4_SYSTEM_RCC_BYPASS | + LM4_SYSTEM_RCC_OSCSRC(1) | + LM4_SYSTEM_RCC_MOSCDIS; + + /* Wait for the PLL to lock */ + clock_wait_cycles(1024); + while (!(LM4_SYSTEM_PLLSTAT & 1)) + ; + + /* Remove bypass on PLL */ + LM4_SYSTEM_RCC &= ~LM4_SYSTEM_RCC_BYPASS; } -/* simple busy waiting before clocks are initialized */ -static void wait_cycles(uint32_t cycles) + +void clock_wait_cycles(uint32_t cycles) { asm("1: subs %0, #1\n" " bne 1b\n" :: "r"(cycles)); } -/** - * Function to measure baseline for power consumption. + +int clock_get_freq(void) +{ + return (LM4_SYSTEM_PLLSTAT & 1) ? PLL_CLOCK : INTERNAL_CLOCK; +} + + +/*****************************************************************************/ +/* Console commands */ + +/* Function to measure baseline for power consumption. * * Levels : * 0 : CPU running in tight loop @@ -47,8 +80,7 @@ static void wait_cycles(uint32_t cycles) * 2 : CPU in sleep mode * 3 : CPU in sleep mode and peripherals gated * 4 : CPU in deep sleep mode - * 5 : CPU in deep sleep mode and peripherals gated - */ + * 5 : CPU in deep sleep mode and peripherals gated */ static int command_sleep(int argc, char **argv) { int level = 0; @@ -146,53 +178,71 @@ static int command_sleep(int argc, char **argv) DECLARE_CONSOLE_COMMAND(sleep, command_sleep); -static void clock_init_pll(uint32_t value) +/* TODO: temporary holding place for notifying modules of clock change. Should + * be moved to main.c after we finish measuring the power savings, so the clock + * frequency is automatically dropped after verified boot. */ +#include "i2c.h" +#include "hwtimer.h" +#include "peci.h" +#include "watchdog.h" + +static int command_disable_pll(int argc, char **argv) { - /** - * at startup, OSCSRC is PIOSC (precision internal oscillator) - * PLL and PLL2 are in power-down - */ + int freq; - /* PLL already setup */ - if (LM4_SYSTEM_PLLSTAT & 1) - return; + clock_disable_pll(); - /* Put a bypass on the system clock PLLs, no divider */ - LM4_SYSTEM_RCC = (LM4_SYSTEM_RCC | 0x800) & ~0x400000; - LM4_SYSTEM_RCC2 = (LM4_SYSTEM_RCC2 | 0x800) & ~0x80000000; + /* Notify modules of frequency change */ + freq = clock_get_freq(); + hwtimer_clock_changed(freq); +#ifdef CONFIG_TASK_WATCHDOG + watchdog_clock_changed(freq); +#endif +#ifdef CONFIG_I2C + i2c_clock_changed(freq); +#endif +#ifdef CONFIG_PECI + peci_clock_changed(freq); +#endif - /* Enable main and precision internal oscillators */ - LM4_SYSTEM_RCC &= ~0x3; + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(nopll, command_disable_pll); - /* Perform an auto calibration of the internal oscillator, using the - * 32.768KHz hibernate clock. */ - /* TODO: (crosbug.com/p/7693) This is only needed on early chips which - * aren't factory trimmed. */ - LM4_SYSTEM_PIOSCCAL = 0x80000000; - LM4_SYSTEM_PIOSCCAL = 0x80000200; +/*****************************************************************************/ +/* Initialization */ - /* wait 1 million CPU cycles */ - wait_cycles(512 * 1024); +int clock_init(void) +{ - /* clear PLL lock flag (aka PLLLMIS) */ - LM4_SYSTEM_MISC = 0x40; - /* clear powerdown / set XTAL frequency, divider, and source */ - LM4_SYSTEM_RCC = (LM4_SYSTEM_RCC & ~0x07c027f0) | (value & 0x07c007f0); - /* wait 32 CPU cycles */ - wait_cycles(16); - /* wait for PLL to lock */ - while (!(LM4_SYSTEM_RIS & 0x40)); +#ifndef BOARD_bds + /* Only BDS has an external crystal; other boards don't have one, and + * can disable main oscillator control to reduce power consumption. */ + LM4_SYSTEM_MOSCCTL = 0x04; +#endif - /* Remove bypass on PLL */ - LM4_SYSTEM_RCC = LM4_SYSTEM_RCC & ~0x800; -} + /* Perform an auto calibration of the internal oscillator using the + * 32.768KHz hibernate clock, unless we've already done so. */ + /* TODO: (crosbug.com/p/7693) This is only needed on early chips which + * aren't factory trimmed. */ + if ((LM4_SYSTEM_PIOSCSTAT & 0x300) != 0x100) { + /* Start calibration */ + LM4_SYSTEM_PIOSCCAL = 0x80000000; + LM4_SYSTEM_PIOSCCAL = 0x80000200; + /* Wait for result */ + clock_wait_cycles(16); + while (!(LM4_SYSTEM_PIOSCSTAT & 0x300)) + ; + } -int clock_init(void) -{ - /* CPU clock = PLL/3 = 66.667MHz; System clock = PLL */ - BUILD_ASSERT(CPU_CLOCK == 66666667); - /* Osc source = internal 16MHz oscillator */ - clock_init_pll(0x01400550); + /* TODO: UART seems to glitch unless we wait 500k cycles before + * enabling the PLL, but only if this is a cold boot. Why? UART + * doesn't even use the PLL'd system clock. I've heard rumors the + * Stellaris ROM library does this too, but why? */ + if (!system_jumped_to_this_image()) + clock_wait_cycles(500000); + + clock_enable_pll(); return EC_SUCCESS; } diff --git a/chip/lm4/hwtimer.c b/chip/lm4/hwtimer.c index 9b221010c8..a45f74705d 100644 --- a/chip/lm4/hwtimer.c +++ b/chip/lm4/hwtimer.c @@ -5,18 +5,14 @@ /* Hardware timers driver */ -#include - #include "board.h" +#include "clock.h" #include "hwtimer.h" #include "registers.h" #include "task.h" #define US_PER_SECOND 1000000 -/* Divider to get microsecond for the clock */ -#define CLOCKSOURCE_DIVIDER (CPU_CLOCK/US_PER_SECOND) - void __hw_clock_event_set(uint32_t deadline) { /* set the match on the deadline */ @@ -57,6 +53,14 @@ static void __hw_clock_source_irq(void) DECLARE_IRQ(LM4_IRQ_TIMERW0A, __hw_clock_source_irq, 1); +void hwtimer_clock_changed(int freq) +{ + /* Set the prescaler to increment every microsecond. This takes + * effect immediately, because the TAILD bit in TAMR is clear. */ + LM4_TIMER_TAPR(6) = freq / US_PER_SECOND; +} + + int __hw_clock_source_init(void) { volatile uint32_t scratch __attribute__((unused)); @@ -75,8 +79,10 @@ int __hw_clock_source_init(void) LM4_TIMER_IMR(6) = 0x1; /* 32-bit timer mode */ LM4_TIMER_CFG(6) = 4; - /* set the prescaler to increment every microsecond */ - LM4_TIMER_TAPR(6) = CLOCKSOURCE_DIVIDER; + + /* Set initial clock frequency */ + hwtimer_clock_changed(clock_get_freq()); + /* Periodic mode, counting down */ LM4_TIMER_TAMR(6) = 0x22; /* use the full 32-bits of the timer */ diff --git a/chip/lm4/i2c.c b/chip/lm4/i2c.c index a6e8a5c77c..131a84a584 100644 --- a/chip/lm4/i2c.c +++ b/chip/lm4/i2c.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ @@ -6,6 +6,7 @@ /* I2C port module for Chrome EC */ #include "board.h" +#include "clock.h" #include "console.h" #include "gpio.h" #include "i2c.h" @@ -58,6 +59,7 @@ static int wait_idle(int port) return EC_SUCCESS; } + /* Transmit one block of raw data, then receive one block of raw data. * flag indicates this smbus session start from idle state. * flag means this session can be termicate with smbus stop bit @@ -142,7 +144,6 @@ static int i2c_transmit_receive(int port, int slave_addr, } - int i2c_read16(int port, int slave_addr, int offset, int *data) { int rv; @@ -192,6 +193,7 @@ int i2c_write16(int port, int slave_addr, int offset, int data) return rv; } + int i2c_read8(int port, int slave_addr, int offset, int* data) { int rv; @@ -210,6 +212,7 @@ int i2c_read8(int port, int slave_addr, int offset, int* data) return rv; } + int i2c_write8(int port, int slave_addr, int offset, int data) { int rv; @@ -226,9 +229,7 @@ int i2c_write8(int port, int slave_addr, int offset, int data) return rv; } -/* Read ascii string using smbus read block protocol. - * The return data will be null terminated. - */ + int i2c_read_string(int port, int slave_addr, int offset, uint8_t *data, int len) { @@ -259,6 +260,18 @@ exit: } +void i2c_clock_changed(int freq) +{ + LM4_I2C_MTPR(I2C_PORT_THERMAL) = + (freq / (I2C_SPEED_THERMAL * 10 * 2)) - 1; + LM4_I2C_MTPR(I2C_PORT_BATTERY) = + (freq / (I2C_SPEED_BATTERY * 10 * 2)) - 1; + LM4_I2C_MTPR(I2C_PORT_CHARGER) = + (freq / (I2C_SPEED_CHARGER * 10 * 2)) - 1; + LM4_I2C_MTPR(I2C_PORT_LIGHTBAR) = + (freq / (I2C_SPEED_LIGHTBAR * 10 * 2)) - 1; +} + /*****************************************************************************/ /* Interrupt handlers */ @@ -439,20 +452,12 @@ int i2c_init(void) /* Initialize ports as master, with interrupts enabled */ LM4_I2C_MCR(I2C_PORT_THERMAL) = 0x10; - LM4_I2C_MTPR(I2C_PORT_THERMAL) = - (CPU_CLOCK / (I2C_SPEED_THERMAL * 10 * 2)) - 1; - LM4_I2C_MCR(I2C_PORT_BATTERY) = 0x10; - LM4_I2C_MTPR(I2C_PORT_BATTERY) = - (CPU_CLOCK / (I2C_SPEED_BATTERY * 10 * 2)) - 1; - LM4_I2C_MCR(I2C_PORT_CHARGER) = 0x10; - LM4_I2C_MTPR(I2C_PORT_CHARGER) = - (CPU_CLOCK / (I2C_SPEED_CHARGER * 10 * 2)) - 1; - LM4_I2C_MCR(I2C_PORT_LIGHTBAR) = 0x10; - LM4_I2C_MTPR(I2C_PORT_LIGHTBAR) = - (CPU_CLOCK / (I2C_SPEED_LIGHTBAR * 10 * 2)) - 1; + + /* Set initial clock frequency */ + i2c_clock_changed(clock_get_freq()); /* Enable irqs */ task_enable_irq(LM4_IRQ_I2C0); diff --git a/chip/lm4/peci.c b/chip/lm4/peci.c index 75946a4e61..2dbbd914b3 100644 --- a/chip/lm4/peci.c +++ b/chip/lm4/peci.c @@ -6,6 +6,7 @@ /* PECI interface for Chrome EC */ #include "board.h" +#include "clock.h" #include "console.h" #include "gpio.h" #include "peci.h" @@ -51,6 +52,7 @@ int peci_get_cpu_temp(void) return v >> 6; } + int peci_temp_sensor_poll(void) { last_temp_val = peci_get_cpu_temp(); @@ -61,11 +63,33 @@ int peci_temp_sensor_poll(void) return EC_ERROR_UNKNOWN; } + int peci_temp_sensor_get_val(int idx) { return last_temp_val; } + +void peci_clock_changed(int freq) +{ + int baud; + + /* Disable polling while reconfiguring */ + LM4_PECI_CTL = 0; + + /* Calculate baud setting from desired rate, compensating for internal + * and external delays. */ + baud = freq / (4 * PECI_BAUD_RATE) - 2; + baud -= (freq / 1000000) * (PECI_TD_FET_NS + PECI_TD_INT_NS) / 1000; + + /* Set baud rate and polling rate */ + LM4_PECI_DIV = (baud << 16) | + (PECI_POLL_INTERVAL_MS * (freq / 1000 / 4096)); + + /* Set up temperature monitoring to report in degrees K */ + LM4_PECI_CTL = ((PECI_TJMAX + 273) << 22) | 0x2001; +} + /*****************************************************************************/ /* Console commands */ @@ -88,7 +112,6 @@ DECLARE_CONSOLE_COMMAND(pecitemp, command_peci_temp); int peci_init(void) { volatile uint32_t scratch __attribute__((unused)); - int baud; /* Enable the PECI module and delay a few clocks */ LM4_SYSTEM_RCGCPECI = 1; @@ -97,21 +120,8 @@ int peci_init(void) /* Configure GPIOs */ configure_gpios(); - /* Disable polling while reconfiguring */ - LM4_PECI_CTL = 0; - - /* Calculate baud setting from desired rate, compensating for internal - * and external delays. */ - baud = CPU_CLOCK / (4 * PECI_BAUD_RATE) - 2; - baud -= (CPU_CLOCK / 1000000) * (PECI_TD_FET_NS + PECI_TD_INT_NS) - / 1000; - - /* Set baud rate and polling rate */ - LM4_PECI_DIV = (baud << 16) | - (PECI_POLL_INTERVAL_MS * (CPU_CLOCK / 1000 / 4096)); - - /* Set up temperature monitoring to report in degrees K */ - LM4_PECI_CTL = ((PECI_TJMAX + 273) << 22) | 0x2001; + /* Set initial clock frequency */ + peci_clock_changed(clock_get_freq()); return EC_SUCCESS; } diff --git a/chip/lm4/registers.h b/chip/lm4/registers.h index a572e763ed..1617e97cd4 100644 --- a/chip/lm4/registers.h +++ b/chip/lm4/registers.h @@ -191,7 +191,17 @@ static inline int lm4_fan_addr(int ch, int offset) #define LM4_SYSTEM_MISC LM4REG(0x400fe058) #define LM4_SYSTEM_RESC LM4REG(0x400fe05c) #define LM4_SYSTEM_RCC LM4REG(0x400fe060) +#define LM4_SYSTEM_RCC_SYSDIV(x) (((x) & 0xf) << 23) +#define LM4_SYSTEM_RCC_USESYSDIV (1 << 22) +#define LM4_SYSTEM_RCC_PWRDN (1 << 13) +#define LM4_SYSTEM_RCC_BYPASS (1 << 11) +#define LM4_SYSTEM_RCC_XTAL(x) (((x) & 0x1f) << 6) +#define LM4_SYSTEM_RCC_OSCSRC(x) (((x) & 0x3) << 4) +#define LM4_SYSTEM_RCC_IOSCDIS (1 << 1) +#define LM4_SYSTEM_RCC_MOSCDIS (1 << 0) #define LM4_SYSTEM_RCC2 LM4REG(0x400fe070) +#define LM4_SYSTEM_RCC2_USERCC2 (1 << 31) +#define LM4_SYSTEM_MOSCCTL LM4REG(0x400fe07c) #define LM4_SYSTEM_PIOSCCAL LM4REG(0x400fe150) #define LM4_SYSTEM_PIOSCSTAT LM4REG(0x400fe154) #define LM4_SYSTEM_PLLSTAT LM4REG(0x400fe168) diff --git a/chip/lm4/watchdog.c b/chip/lm4/watchdog.c index ca76da2c24..248d895369 100644 --- a/chip/lm4/watchdog.c +++ b/chip/lm4/watchdog.c @@ -1,13 +1,12 @@ -/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ /* Watchdog driver */ -#include - #include "board.h" +#include "clock.h" #include "common.h" #include "config.h" #include "registers.h" @@ -25,8 +24,9 @@ /* magic value to unlock the watchdog registers */ #define LM4_WATCHDOG_MAGIC_WORD 0x1ACCE551 -/* watchdog counter initial value */ -static uint32_t watchdog_period; +#define WATCHDOG_PERIOD_MS 1100 /* Watchdog period in ms */ + +static uint32_t watchdog_period; /* Watchdog counter initial value */ /* console debug command prototypes */ int command_task_info(int argc, char **argv); @@ -110,7 +110,15 @@ void watchdog_reload(void) LM4_WATCHDOG_LOCK(0) = 0xdeaddead; } -int watchdog_init(int period_ms) + +void watchdog_clock_changed(int freq) +{ + /* Set the timeout period */ + watchdog_period = WATCHDOG_PERIOD_MS * (freq / 1000); +} + + +int watchdog_init(void) { volatile uint32_t scratch __attribute__((unused)); @@ -122,8 +130,8 @@ int watchdog_init(int period_ms) /* Unlock watchdog registers */ LM4_WATCHDOG_LOCK(0) = LM4_WATCHDOG_MAGIC_WORD; - /* Set the time-out period */ - watchdog_period = period_ms * (CPU_CLOCK / 1000); + /* Set initial timeout period */ + watchdog_clock_changed(clock_get_freq()); LM4_WATCHDOG_LOAD(0) = watchdog_period; /* de-activate the watchdog when the JTAG stops the CPU */ diff --git a/chip/stm32l/clock.c b/chip/stm32l/clock.c index 9b4c01ab73..aa243738b0 100644 --- a/chip/stm32l/clock.c +++ b/chip/stm32l/clock.c @@ -13,19 +13,6 @@ #include "registers.h" #include "util.h" -/** - * Idle task - * executed when no task are ready to be scheduled - */ -void __idle(void) -{ - while (1) { - /* wait for the irq event */ - asm("wfi"); - /* TODO more power management here */ - } -} - int clock_init(void) { uint32_t tmp_acr; diff --git a/core/cortex-m/task.c b/core/cortex-m/task.c index 1f15bf5df6..34c12d674c 100644 --- a/core/cortex-m/task.c +++ b/core/cortex-m/task.c @@ -35,7 +35,7 @@ typedef union { /* declare task routine prototypes */ #define TASK(n, r, d) int r(void *); #include TASK_LIST -void __idle(void); +static void __idle(void); CONFIG_TASK_LIST #undef TASK @@ -51,6 +51,17 @@ static const char * const task_names[] = { extern void __switchto(task_ *from, task_ *to); +/* Idle task. Executed when no tasks are ready to be scheduled. */ +void __idle(void) +{ + while (1) { + /* Wait for the irq event */ + asm("wfi"); + /* TODO: more power management here */ + } +} + + static void task_exit_trap(void) { int i = task_get_current(); diff --git a/core/cortex-m/timer.c b/core/cortex-m/timer.c index a679e8d7b5..8d98287c46 100644 --- a/core/cortex-m/timer.c +++ b/core/cortex-m/timer.c @@ -167,7 +167,8 @@ DECLARE_CONSOLE_COMMAND(waitms, command_wait); static int command_get_time(int argc, char **argv) { timestamp_t ts = get_time(); - uart_printf("Time: 0x%08x%08x us\n", ts.le.hi, ts.le.lo); + uart_printf("Time: 0x%08x%08x us (%u %u)\n", ts.le.hi, ts.le.lo, + ts.le.hi, ts.le.lo); return EC_SUCCESS; } diff --git a/include/clock.h b/include/clock.h index c4008672ef..081c9c95a9 100644 --- a/include/clock.h +++ b/include/clock.h @@ -1,14 +1,23 @@ -/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ /* Clocks and power management settings */ -#ifndef __CLOCK_H -#define __CLOCK_H +#ifndef __CROS_EC_CLOCK_H +#define __CROS_EC_CLOCK_H -/* set the CPU clocks and PLLs */ +#include "common.h" + +/* Set the CPU clocks and PLLs. */ int clock_init(void); -#endif /* __CLOCK_H */ +/* Returns the current clock frequency in Hz. */ +int clock_get_freq(void); + +/* Wait system clock cycles. Simple busy waiting for before + * clocks/timers are initialized. */ +void clock_wait_cycles(uint32_t cycles); + +#endif /* __CROS_EC_CLOCK_H */ diff --git a/include/hwtimer.h b/include/hwtimer.h index 384e3613dd..5fee466b7c 100644 --- a/include/hwtimer.h +++ b/include/hwtimer.h @@ -30,6 +30,9 @@ uint32_t __hw_clock_source_read(void); */ int __hw_clock_source_init(void); +/* Notifies the module the system clock frequency has changed to . */ +void hwtimer_clock_changed(int freq); + /** * Searches the next deadline and program it in the timer hardware. * diff --git a/include/i2c.h b/include/i2c.h index 701992e35e..22ab18adcf 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ @@ -16,6 +16,9 @@ /* Initializes the module. */ int i2c_init(void); +/* Notifies the module the system clock frequency has changed to . */ +void i2c_clock_changed(int freq); + /* Reads a 16-bit register from the slave at 8-bit slave address * , at the specified 8-bit in the slave's address * space. */ diff --git a/include/peci.h b/include/peci.h index 2b2c33f4a7..7a98a24991 100644 --- a/include/peci.h +++ b/include/peci.h @@ -15,6 +15,9 @@ struct temp_sensor_t; /* Initializes the module. */ int peci_init(void); +/* Notifies the module the system clock frequency has changed to . */ +void peci_clock_changed(int freq); + /* Returns the current CPU temperature in degrees K, or -1 if error. * * Note that the PECI interface is currently a little flaky; if you get an diff --git a/include/watchdog.h b/include/watchdog.h index 75a5e0b4a5..569352bc6a 100644 --- a/include/watchdog.h +++ b/include/watchdog.h @@ -1,21 +1,21 @@ -/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ /* Watchdog driver */ -#ifndef _WATCHDOG_H -#define _WATCHDOG_H +#ifndef __CROS_EC_WATCHDOG_H +#define __CROS_EC_WATCHDOG_H + +/* Initialize the watchdog. This will cause the CPU to reboot if it has been + * more than 2 watchdog periods since watchdog_reload() has been called. */ +int watchdog_init(int period_ms); /* Reload the watchdog counter */ void watchdog_reload(void); -/** - * Initialize the watchdog - * with a reloading period of milliseconds. - * It reboots the CPU if the counter has not been reloaded for twice the period. - */ -int watchdog_init(int period_ms); +/* Notifies the module the system clock frequency has changed to . */ +void watchdog_clock_changed(int freq); -#endif /* _WATCHDOG_H */ +#endif /* __CROS_EC_WATCHDOG_H */ diff --git a/test/powerdemo.c b/test/powerdemo.c index aabe4c8825..496459f9f7 100644 --- a/test/powerdemo.c +++ b/test/powerdemo.c @@ -6,16 +6,14 @@ /* Power state machine demo module for Chrome EC */ #include "board.h" +#include "clock.h" #include "powerdemo.h" #include "task.h" #include "timer.h" #include "uart.h" #include "registers.h" - #define US_PER_SECOND 1000000 -/* Divider to get microsecond for the clock */ -#define CLOCKSOURCE_DIVIDER (CPU_CLOCK/US_PER_SECOND) static volatile enum { POWER_STATE_IDLE = 0, /* Idle */ @@ -77,7 +75,7 @@ int power_demo_init(void) /* 32-bit timer mode */ LM4_TIMER_CFG(7) = 4; /* Set the prescaler to increment every microsecond */ - LM4_TIMER_TAPR(7) = CLOCKSOURCE_DIVIDER; + LM4_TIMER_TAPR(7) = clock_get_freq() / US_PER_SECOND; /* One-shot, counting down */ LM4_TIMER_TAMR(7) = 0x01; /* Set overflow interrupt */ -- cgit v1.2.1