summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2013-10-08 16:46:58 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2013-10-10 23:14:20 +0000
commit27e063ea100086a913ed655b611c88e077de5b00 (patch)
tree701999fd9367e30d008179243a0fc95fc51c5175
parentf7e69a211ce0121ec06c79f6d82574d3347dec2f (diff)
downloadchrome-ec-27e063ea100086a913ed655b611c88e077de5b00.tar.gz
lm4: Modified clock gating to allow easy expansion to low power.
Created a new function to enable or disable clocks to various peripherals. This new function makes it easy to specify if you want the clock enabled in run mode, sleep mode, and/or deep sleep mode. Added infrastructure to specify which GPIOs should interrupt the EC from deep sleep. BUG=none BRANCH=none TEST=Passes all unit tests. Ran on a peppy and verified that the clock gate control registers in run mode (LM4_RCGC regs) were the same before and after this change. Change-Id: Ia5009ac8c837f61dca52fe86ebdeede2e1a7fe4d Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/172454 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--chip/lm4/adc.c6
-rw-r--r--chip/lm4/clock.c132
-rw-r--r--chip/lm4/eeprom.c6
-rw-r--r--chip/lm4/gpio.c50
-rw-r--r--chip/lm4/hwtimer.c9
-rw-r--r--chip/lm4/i2c.c6
-rw-r--r--chip/lm4/jtag.c6
-rw-r--r--chip/lm4/lpc.c6
-rw-r--r--chip/lm4/peci.c6
-rw-r--r--chip/lm4/pwm.c4
-rw-r--r--chip/lm4/registers.h40
-rw-r--r--chip/lm4/spi.c8
-rw-r--r--chip/lm4/system.c12
-rw-r--r--chip/lm4/uart.c10
-rw-r--r--chip/lm4/watchdog.c8
-rw-r--r--include/clock.h26
-rw-r--r--include/config.h1
-rw-r--r--include/gpio.h2
18 files changed, 264 insertions, 74 deletions
diff --git a/chip/lm4/adc.c b/chip/lm4/adc.c
index 17f3d26191..1456ba996b 100644
--- a/chip/lm4/adc.c
+++ b/chip/lm4/adc.c
@@ -203,9 +203,9 @@ static void adc_init(void)
*/
clock_enable_pll(1, 0);
- /* Enable ADC0 module and delay a few clocks. */
- LM4_SYSTEM_RCGCADC = 1;
- clock_wait_cycles(3);
+ /* Enable ADC0 module in run and sleep modes. */
+ clock_enable_peripheral(CGC_OFFSET_ADC, 0x1,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
/*
* Use external voltage references (VREFA+, VREFA-) instead of
diff --git a/chip/lm4/clock.c b/chip/lm4/clock.c
index 02f955776e..2d7365f9ab 100644
--- a/chip/lm4/clock.c
+++ b/chip/lm4/clock.c
@@ -128,6 +128,33 @@ void clock_init(void)
disable_pll();
}
+void clock_enable_peripheral(uint32_t offset, uint32_t mask, uint32_t mode)
+{
+ if (mode & CGC_MODE_RUN)
+ *(LM4_SYSTEM_RCGC_BASE + offset) |= mask;
+
+ if (mode & CGC_MODE_SLEEP)
+ *(LM4_SYSTEM_SCGC_BASE + offset) |= mask;
+
+ if (mode & CGC_MODE_DSLEEP)
+ *(LM4_SYSTEM_DCGC_BASE + offset) |= mask;
+
+ /* Wait for clock change to take affect. */
+ clock_wait_cycles(3);
+}
+
+void clock_disable_peripheral(uint32_t offset, uint32_t mask, uint32_t mode)
+{
+ if (mode & CGC_MODE_RUN)
+ *(LM4_SYSTEM_RCGC_BASE + offset) &= ~mask;
+
+ if (mode & CGC_MODE_SLEEP)
+ *(LM4_SYSTEM_SCGC_BASE + offset) &= ~mask;
+
+ if (mode & CGC_MODE_DSLEEP)
+ *(LM4_SYSTEM_DCGC_BASE + offset) &= ~mask;
+}
+
/*****************************************************************************/
/* Console commands */
@@ -218,12 +245,18 @@ static int command_sleep(int argc, char **argv)
/* gate peripheral clocks */
if (level & 1) {
- LM4_SYSTEM_RCGCTIMER = 0;
- LM4_SYSTEM_RCGCGPIO = 0;
- LM4_SYSTEM_RCGCDMA = 0;
- LM4_SYSTEM_RCGCUART = 0;
- LM4_SYSTEM_RCGCLPC = 0;
- LM4_SYSTEM_RCGCWTIMER = 0;
+ clock_disable_peripheral(CGC_OFFSET_TIMER, 0xffffffff,
+ CGC_MODE_ALL);
+ clock_disable_peripheral(CGC_OFFSET_GPIO, 0xffffffff,
+ CGC_MODE_ALL);
+ clock_disable_peripheral(CGC_OFFSET_DMA, 0xffffffff,
+ CGC_MODE_ALL);
+ clock_disable_peripheral(CGC_OFFSET_UART, 0xffffffff,
+ CGC_MODE_ALL);
+ clock_disable_peripheral(CGC_OFFSET_LPC, 0xffffffff,
+ CGC_MODE_ALL);
+ clock_disable_peripheral(CGC_OFFSET_WTIMER, 0xffffffff,
+ CGC_MODE_ALL);
}
/* set deep sleep bit */
if (level >= 4)
@@ -289,3 +322,90 @@ DECLARE_CONSOLE_COMMAND(pll, command_pll,
NULL);
#endif /* CONFIG_CMD_PLL */
+
+#ifdef CONFIG_CMD_CLOCKGATES
+/**
+ * Print all clock gating registers
+ */
+static int command_clock_gating(int argc, char **argv)
+{
+ ccprintf(" Run , Sleep , Deep Sleep\n");
+
+ ccprintf("WD: 0x%08x, ",
+ *(LM4_SYSTEM_RCGC_BASE + CGC_OFFSET_WD));
+ ccprintf("0x%08x, ", *(LM4_SYSTEM_SCGC_BASE + CGC_OFFSET_WD));
+ ccprintf("0x%08x\n", *(LM4_SYSTEM_DCGC_BASE + CGC_OFFSET_WD));
+
+ ccprintf("TIMER: 0x%08x, ",
+ *(LM4_SYSTEM_RCGC_BASE + CGC_OFFSET_TIMER));
+ ccprintf("0x%08x, ", *(LM4_SYSTEM_SCGC_BASE + CGC_OFFSET_TIMER));
+ ccprintf("0x%08x\n", *(LM4_SYSTEM_DCGC_BASE + CGC_OFFSET_TIMER));
+
+ ccprintf("GPIO: 0x%08x, ",
+ *(LM4_SYSTEM_RCGC_BASE + CGC_OFFSET_GPIO));
+ ccprintf("0x%08x, ", *(LM4_SYSTEM_SCGC_BASE + CGC_OFFSET_GPIO));
+ ccprintf("0x%08x\n", *(LM4_SYSTEM_DCGC_BASE + CGC_OFFSET_GPIO));
+
+ ccprintf("DMA: 0x%08x, ",
+ *(LM4_SYSTEM_RCGC_BASE + CGC_OFFSET_DMA));
+ ccprintf("0x%08x, ", *(LM4_SYSTEM_SCGC_BASE + CGC_OFFSET_DMA));
+ ccprintf("0x%08x\n", *(LM4_SYSTEM_DCGC_BASE + CGC_OFFSET_DMA));
+
+ ccprintf("HIB: 0x%08x, ",
+ *(LM4_SYSTEM_RCGC_BASE + CGC_OFFSET_HIB));
+ ccprintf("0x%08x, ", *(LM4_SYSTEM_SCGC_BASE + CGC_OFFSET_HIB));
+ ccprintf("0x%08x\n", *(LM4_SYSTEM_DCGC_BASE + CGC_OFFSET_HIB));
+
+ ccprintf("UART: 0x%08x, ",
+ *(LM4_SYSTEM_RCGC_BASE + CGC_OFFSET_UART));
+ ccprintf("0x%08x, ", *(LM4_SYSTEM_SCGC_BASE + CGC_OFFSET_UART));
+ ccprintf("0x%08x\n", *(LM4_SYSTEM_DCGC_BASE + CGC_OFFSET_UART));
+
+ ccprintf("SSI: 0x%08x, ",
+ *(LM4_SYSTEM_RCGC_BASE + CGC_OFFSET_SSI));
+ ccprintf("0x%08x, ", *(LM4_SYSTEM_SCGC_BASE + CGC_OFFSET_SSI));
+ ccprintf("0x%08x\n", *(LM4_SYSTEM_DCGC_BASE + CGC_OFFSET_SSI));
+
+ ccprintf("I2C: 0x%08x, ",
+ *(LM4_SYSTEM_RCGC_BASE + CGC_OFFSET_I2C));
+ ccprintf("0x%08x, ", *(LM4_SYSTEM_SCGC_BASE + CGC_OFFSET_I2C));
+ ccprintf("0x%08x\n", *(LM4_SYSTEM_DCGC_BASE + CGC_OFFSET_I2C));
+
+ ccprintf("ADC: 0x%08x, ",
+ *(LM4_SYSTEM_RCGC_BASE + CGC_OFFSET_ADC));
+ ccprintf("0x%08x, ", *(LM4_SYSTEM_SCGC_BASE + CGC_OFFSET_ADC));
+ ccprintf("0x%08x\n", *(LM4_SYSTEM_DCGC_BASE + CGC_OFFSET_ADC));
+
+ ccprintf("LPC: 0x%08x, ",
+ *(LM4_SYSTEM_RCGC_BASE + CGC_OFFSET_LPC));
+ ccprintf("0x%08x, ", *(LM4_SYSTEM_SCGC_BASE + CGC_OFFSET_LPC));
+ ccprintf("0x%08x\n", *(LM4_SYSTEM_DCGC_BASE + CGC_OFFSET_LPC));
+
+ ccprintf("PECI: 0x%08x, ",
+ *(LM4_SYSTEM_RCGC_BASE + CGC_OFFSET_PECI));
+ ccprintf("0x%08x, ", *(LM4_SYSTEM_SCGC_BASE + CGC_OFFSET_PECI));
+ ccprintf("0x%08x\n", *(LM4_SYSTEM_DCGC_BASE + CGC_OFFSET_PECI));
+
+ ccprintf("FAN: 0x%08x, ",
+ *(LM4_SYSTEM_RCGC_BASE + CGC_OFFSET_FAN));
+ ccprintf("0x%08x, ", *(LM4_SYSTEM_SCGC_BASE + CGC_OFFSET_FAN));
+ ccprintf("0x%08x\n", *(LM4_SYSTEM_DCGC_BASE + CGC_OFFSET_FAN));
+
+ ccprintf("EEPROM: 0x%08x, ",
+ *(LM4_SYSTEM_RCGC_BASE + CGC_OFFSET_EEPROM));
+ ccprintf("0x%08x, ", *(LM4_SYSTEM_SCGC_BASE + CGC_OFFSET_EEPROM));
+ ccprintf("0x%08x\n", *(LM4_SYSTEM_DCGC_BASE + CGC_OFFSET_EEPROM));
+
+ ccprintf("WTIMER: 0x%08x, ",
+ *(LM4_SYSTEM_RCGC_BASE + CGC_OFFSET_WTIMER));
+ ccprintf("0x%08x, ", *(LM4_SYSTEM_SCGC_BASE + CGC_OFFSET_WTIMER));
+ ccprintf("0x%08x\n", *(LM4_SYSTEM_DCGC_BASE + CGC_OFFSET_WTIMER));
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(clockgates, command_clock_gating,
+ "",
+ "Get state of the clock gating controls regs",
+ NULL);
+#endif /* CONFIG_CMD_CLOCKGATES */
+
diff --git a/chip/lm4/eeprom.c b/chip/lm4/eeprom.c
index 2a0fa8935c..6ebf82a980 100644
--- a/chip/lm4/eeprom.c
+++ b/chip/lm4/eeprom.c
@@ -240,9 +240,9 @@ DECLARE_CONSOLE_COMMAND(eehide, command_eeprom_hide,
int eeprom_init(void)
{
- /* Enable the EEPROM module and delay a few clocks */
- LM4_SYSTEM_RCGCEEPROM = 1;
- clock_wait_cycles(6);
+ /* Enable the EEPROM module in run and sleep modes. */
+ clock_enable_peripheral(CGC_OFFSET_EEPROM, 0x1,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
/* Wait for internal EEPROM init to finish */
wait_for_done();
diff --git a/chip/lm4/gpio.c b/chip/lm4/gpio.c
index 5834d4b7e5..a6aeeaa58f 100644
--- a/chip/lm4/gpio.c
+++ b/chip/lm4/gpio.c
@@ -50,13 +50,10 @@ void gpio_set_alternate_function(uint32_t port, uint32_t mask, int func)
if (port_index < 0)
return; /* TODO: assert */
- /* Enable the GPIO port if necessary */
+ /* Enable the GPIO port in run and sleep. */
cgmask = 1 << port_index;
- if ((LM4_SYSTEM_RCGCGPIO & cgmask) != cgmask) {
- LM4_SYSTEM_RCGCGPIO |= cgmask;
- /* Delay a few clocks before accessing registers */
- clock_wait_cycles(3);
- }
+ clock_enable_peripheral(CGC_OFFSET_GPIO, cgmask,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
if (func >= 0) {
int pctlmask = 0;
@@ -159,6 +156,19 @@ int gpio_enable_interrupt(enum gpio_signal signal)
return EC_SUCCESS;
}
+#ifdef CONFIG_LOW_POWER_IDLE
+/**
+ * Convert GPIO port to a mask that can be used to set the
+ * clock gate control register for GPIOs.
+ */
+static int gpio_port_to_clock_gate_mask(uint32_t gpio_port)
+{
+ int index = find_gpio_port_index(gpio_port);
+
+ return index >= 0 ? (1 << index) : 0;
+}
+#endif
+
void gpio_pre_init(void)
{
const struct gpio_info *g = gpio_list;
@@ -171,10 +181,10 @@ void gpio_pre_init(void)
} else {
/*
* Enable clocks to all the GPIO blocks since we use all of
- * them as GPIOs.
+ * them as GPIOs in run and sleep modes.
*/
- LM4_SYSTEM_RCGCGPIO |= 0x7fff;
- clock_wait_cycles(6); /* Delay a few clocks */
+ clock_enable_peripheral(CGC_OFFSET_GPIO, 0x7fff,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
}
/*
@@ -202,6 +212,18 @@ void gpio_pre_init(void)
if (flags & GPIO_DEFAULT)
continue;
+#ifdef CONFIG_LOW_POWER_IDLE
+ /*
+ * Enable board specific GPIO ports to interrupt deep sleep by
+ * providing a clock to that port in deep sleep mode.
+ */
+ if (flags & GPIO_INT_DSLEEP) {
+ clock_enable_peripheral(CGC_OFFSET_GPIO,
+ gpio_port_to_clock_gate_mask(g->port),
+ CGC_MODE_ALL);
+ }
+#endif
+
/*
* If this is a warm reboot, don't set the output levels or
* we'll shut off the main chipset.
@@ -215,6 +237,16 @@ void gpio_pre_init(void)
/* Use as GPIO, not alternate function */
gpio_set_alternate_function(g->port, g->mask, -1);
}
+
+#ifdef CONFIG_LOW_POWER_IDLE
+ /*
+ * Enable KB scan row to interrupt deep sleep by providing a clock
+ * signal to that port in deep sleep mode.
+ */
+ clock_enable_peripheral(CGC_OFFSET_GPIO,
+ gpio_port_to_clock_gate_mask(KB_SCAN_ROW_GPIO),
+ CGC_MODE_ALL);
+#endif
}
/* List of GPIO IRQs to enable. Don't automatically enable interrupts for
diff --git a/chip/lm4/hwtimer.c b/chip/lm4/hwtimer.c
index cbf28f5294..088bd5713b 100644
--- a/chip/lm4/hwtimer.c
+++ b/chip/lm4/hwtimer.c
@@ -69,17 +69,14 @@ DECLARE_HOOK(HOOK_FREQ_CHANGE, update_prescaler, HOOK_PRIO_DEFAULT);
int __hw_clock_source_init(uint32_t start_t)
{
- volatile uint32_t scratch __attribute__((unused));
-
/*
* Use WTIMER0 (timer 6) configured as a free running counter with 1 us
* period.
*/
- /* Enable WTIMER0 clock */
- LM4_SYSTEM_RCGCWTIMER |= 1;
- /* wait 3 clock cycles before using the module */
- scratch = LM4_SYSTEM_RCGCWTIMER;
+ /* Enable WTIMER0 clock in run and sleep modes. */
+ clock_enable_peripheral(CGC_OFFSET_WTIMER, 0x1,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
/* Ensure timer is disabled : TAEN = TBEN = 0 */
LM4_TIMER_CTL(6) &= ~0x101;
diff --git a/chip/lm4/i2c.c b/chip/lm4/i2c.c
index cf2ff5a690..44bec4e2f6 100644
--- a/chip/lm4/i2c.c
+++ b/chip/lm4/i2c.c
@@ -276,12 +276,12 @@ static void i2c_init(void)
uint32_t mask = 0;
int i;
- /* Enable I2C modules and delay a few clocks */
+ /* Enable I2C modules in run and sleep modes. */
for (i = 0; i < i2c_ports_used; i++)
mask |= 1 << i2c_ports[i].port;
- LM4_SYSTEM_RCGCI2C |= mask;
- clock_wait_cycles(3);
+ clock_enable_peripheral(CGC_OFFSET_I2C, mask,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
/* Configure GPIOs */
gpio_config_module(MODULE_I2C, 1);
diff --git a/chip/lm4/jtag.c b/chip/lm4/jtag.c
index bfa9b1e7de..6b59d7fead 100644
--- a/chip/lm4/jtag.c
+++ b/chip/lm4/jtag.c
@@ -3,13 +3,15 @@
* found in the LICENSE file.
*/
+#include "clock.h"
#include "jtag.h"
#include "registers.h"
void jtag_pre_init(void)
{
- /* Enable clocks to GPIO block C */
- LM4_SYSTEM_RCGCGPIO |= 0x0004;
+ /* Enable clocks to GPIO block C in run and sleep modes. */
+ clock_enable_peripheral(CGC_OFFSET_GPIO, 0x0004,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
/*
* Ensure PC0:3 are set to JTAG function. They should be set this way
diff --git a/chip/lm4/lpc.c b/chip/lm4/lpc.c
index db4e4e0067..8f24bb2ed2 100644
--- a/chip/lm4/lpc.c
+++ b/chip/lm4/lpc.c
@@ -677,9 +677,9 @@ static void lpc_post_sysjump(void)
static void lpc_init(void)
{
- /* Enable RGCGLPC then delay a few clocks. */
- LM4_SYSTEM_RCGCLPC = 1;
- clock_wait_cycles(6);
+ /* Enable LPC clock in run and sleep modes. */
+ clock_enable_peripheral(CGC_OFFSET_LPC, 0x1,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
LM4_LPC_LPCIM = 0;
LM4_LPC_LPCCTL = 0;
diff --git a/chip/lm4/peci.c b/chip/lm4/peci.c
index d753c52730..7f0d692439 100644
--- a/chip/lm4/peci.c
+++ b/chip/lm4/peci.c
@@ -110,9 +110,9 @@ static void peci_init(void)
{
int i;
- /* Enable the PECI module and delay a few clocks */
- LM4_SYSTEM_RCGCPECI = 1;
- clock_wait_cycles(3);
+ /* Enable the PECI module in run and sleep modes. */
+ clock_enable_peripheral(CGC_OFFSET_PECI, 0x1,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
/* Configure GPIOs */
gpio_config_module(MODULE_PECI, 1);
diff --git a/chip/lm4/pwm.c b/chip/lm4/pwm.c
index 68aae8fc8c..c9d1dbe4a4 100644
--- a/chip/lm4/pwm.c
+++ b/chip/lm4/pwm.c
@@ -76,8 +76,8 @@ static void pwm_init(void)
const struct pwm_t *pwm;
/* Enable the fan module and delay a few clocks */
- LM4_SYSTEM_RCGCFAN = 1;
- clock_wait_cycles(3);
+ clock_enable_peripheral(CGC_OFFSET_FAN, 0x1,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
/* Disable all fans */
LM4_FAN_FANCTL = 0;
diff --git a/chip/lm4/registers.h b/chip/lm4/registers.h
index c463fe41cc..9450afea39 100644
--- a/chip/lm4/registers.h
+++ b/chip/lm4/registers.h
@@ -254,20 +254,34 @@ static inline int lm4_fan_addr(int ch, int offset)
#define LM4_SYSTEM_USER_REG3 REG32(0x400fe1ec)
#define LM4_SYSTEM_SRI2C REG32(0x400fe520)
#define LM4_SYSTEM_SREEPROM REG32(0x400fe558)
-#define LM4_SYSTEM_RCGCWD REG32(0x400fe600)
-#define LM4_SYSTEM_RCGCTIMER REG32(0x400fe604)
+
+#define LM4_SYSTEM_RCGC_BASE ((volatile uint32_t *)0x400fe600)
#define LM4_SYSTEM_RCGCGPIO REG32(0x400fe608)
-#define LM4_SYSTEM_RCGCDMA REG32(0x400fe60c)
-#define LM4_SYSTEM_RCGCHIB REG32(0x400fe614)
-#define LM4_SYSTEM_RCGCUART REG32(0x400fe618)
-#define LM4_SYSTEM_RCGCSSI REG32(0x400fe61c)
-#define LM4_SYSTEM_RCGCI2C REG32(0x400fe620)
-#define LM4_SYSTEM_RCGCADC REG32(0x400fe638)
-#define LM4_SYSTEM_RCGCLPC REG32(0x400fe648)
-#define LM4_SYSTEM_RCGCPECI REG32(0x400fe650)
-#define LM4_SYSTEM_RCGCFAN REG32(0x400fe654)
-#define LM4_SYSTEM_RCGCEEPROM REG32(0x400fe658)
-#define LM4_SYSTEM_RCGCWTIMER REG32(0x400fe65c)
+#define LM4_SYSTEM_SCGC_BASE ((volatile uint32_t *)0x400fe700)
+#define LM4_SYSTEM_DCGC_BASE ((volatile uint32_t *)0x400fe800)
+
+/*
+ * Offsets from CGC_BASE registers for each peripheral.
+ * Note: these are in units of 32-bit words offset from
+ * the base address.
+ */
+enum clock_gate_offsets {
+ CGC_OFFSET_WD = 0,
+ CGC_OFFSET_TIMER = 1,
+ CGC_OFFSET_GPIO = 2,
+ CGC_OFFSET_DMA = 3,
+ CGC_OFFSET_HIB = 5,
+ CGC_OFFSET_UART = 6,
+ CGC_OFFSET_SSI = 7,
+ CGC_OFFSET_I2C = 8,
+ CGC_OFFSET_ADC = 14,
+ CGC_OFFSET_LPC = 18,
+ CGC_OFFSET_PECI = 20,
+ CGC_OFFSET_FAN = 21,
+ CGC_OFFSET_EEPROM = 22,
+ CGC_OFFSET_WTIMER = 23,
+};
+
#define LM4_SYSTEM_PREEPROM REG32(0x400fea58)
#define LM4_DMA_DMACFG REG32(0x400ff004)
diff --git a/chip/lm4/spi.c b/chip/lm4/spi.c
index 6526ded82c..914e5f1c66 100644
--- a/chip/lm4/spi.c
+++ b/chip/lm4/spi.c
@@ -99,11 +99,9 @@ int spi_transaction(const uint8_t *txdata, int txlen,
static int spi_init(void)
{
- volatile uint32_t scratch __attribute__((unused));
-
- /* Enable the SPI module and delay a few clocks */
- LM4_SYSTEM_RCGCSSI = 1;
- scratch = LM4_SYSTEM_RCGCSSI;
+ /* Enable the SPI module in run and sleep modes */
+ clock_enable_peripheral(CGC_OFFSET_SSI, 0x1,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
LM4_SSI_CR1(0) = 0; /* Disable SSI */
LM4_SSI_CR0(0) = 0x0007; /* SCR=0, SPH=0, SPO=0, FRF=SPI, 8-bit */
diff --git a/chip/lm4/system.c b/chip/lm4/system.c
index 46d2fa68da..33bfd0227c 100644
--- a/chip/lm4/system.c
+++ b/chip/lm4/system.c
@@ -5,6 +5,7 @@
/* System module for Chrome EC : LM4 hardware specific implementation */
+#include "clock.h"
#include "common.h"
#include "console.h"
#include "cpu.h"
@@ -295,12 +296,11 @@ void system_hibernate(uint32_t seconds, uint32_t microseconds)
void system_pre_init(void)
{
- volatile uint32_t scratch __attribute__((unused));
-
- /* Enable clocks to the hibernation module */
- LM4_SYSTEM_RCGCHIB = 1;
- /* Wait 3 clock cycles before using the module */
- scratch = LM4_SYSTEM_RCGCHIB;
+ /*
+ * Enable clocks to the hibernation module in run, sleep,
+ * and deep sleep modes.
+ */
+ clock_enable_peripheral(CGC_OFFSET_HIB, 0x1, CGC_MODE_ALL);
/*
* Enable the hibernation oscillator, if it's not already enabled.
diff --git a/chip/lm4/uart.c b/chip/lm4/uart.c
index 75f6fa0724..13fad41be6 100644
--- a/chip/lm4/uart.c
+++ b/chip/lm4/uart.c
@@ -180,14 +180,16 @@ static void uart_config(int port)
void uart_init(void)
{
- /* Enable UART0 and Host UART and delay a few clocks */
- LM4_SYSTEM_RCGCUART |= 1;
+ uint32_t mask = 0;
+
+ /* Enable UART0 and Host UART in run, sleep, and deep sleep modes. */
+ mask |= 1;
#ifdef CONFIG_UART_HOST
- LM4_SYSTEM_RCGCUART |= (1 << CONFIG_UART_HOST);
+ mask |= (1 << CONFIG_UART_HOST);
#endif
- clock_wait_cycles(3);
+ clock_enable_peripheral(CGC_OFFSET_UART, mask, CGC_MODE_ALL);
gpio_config_module(MODULE_UART, 1);
diff --git a/chip/lm4/watchdog.c b/chip/lm4/watchdog.c
index ef817cf715..56f051bcd8 100644
--- a/chip/lm4/watchdog.c
+++ b/chip/lm4/watchdog.c
@@ -91,12 +91,8 @@ DECLARE_HOOK(HOOK_FREQ_CHANGE, watchdog_freq_changed, HOOK_PRIO_DEFAULT);
int watchdog_init(void)
{
- volatile uint32_t scratch __attribute__((unused));
-
- /* Enable watchdog 0 clock */
- LM4_SYSTEM_RCGCWD |= 0x1;
- /* Wait 3 clock cycles before using the module */
- scratch = LM4_SYSTEM_RCGCWD;
+ /* Enable watchdog 0 clock in run, sleep, and deep sleep modes */
+ clock_enable_peripheral(CGC_OFFSET_WD, 0x1, CGC_MODE_ALL);
/* Set initial timeout period */
watchdog_freq_changed();
diff --git a/include/clock.h b/include/clock.h
index 6703249076..343b43ecee 100644
--- a/include/clock.h
+++ b/include/clock.h
@@ -67,6 +67,32 @@ enum {
SLEEP_MASK_FORCE = (1 << 31), /* Force disabling low power modes */
};
+/* Clock gate control modes for clock_enable_peripheral() */
+#define CGC_MODE_RUN (1 << 0)
+#define CGC_MODE_SLEEP (1 << 1)
+#define CGC_MODE_DSLEEP (1 << 2)
+#define CGC_MODE_ALL (CGC_MODE_RUN | CGC_MODE_SLEEP | CGC_MODE_DSLEEP)
+
+/**
+ * Enable clock to peripheral by setting the CGC register pertaining
+ * to run, sleep, and/or deep sleep modes.
+ *
+ * @param offset Offset of the peripheral. See enum clock_gate_offsets.
+ * @param mask Bit mask of the bits within CGC reg to set.
+ * @param mode Which mode(s) to enable the clock for
+ */
+void clock_enable_peripheral(uint32_t offset, uint32_t mask, uint32_t mode);
+
+/**
+ * Disable clock to peripheral by setting the CGC register pertaining
+ * to run, sleep, and/or deep sleep modes.
+ *
+ * @param offset Offset of the peripheral. See enum clock_gate_offsets.
+ * @param mask Bit mask of the bits within CGC reg to clear.
+ * @param mode Which mode(s) to enable the clock for
+ */
+void clock_disable_peripheral(uint32_t offset, uint32_t mask, uint32_t mode);
+
void enable_sleep(uint32_t mask);
void disable_sleep(uint32_t mask);
diff --git a/include/config.h b/include/config.h
index 7887c862e2..09478a1557 100644
--- a/include/config.h
+++ b/include/config.h
@@ -204,6 +204,7 @@
* console.
*/
+#undef CONFIG_CMD_CLOCKGATES
#undef CONFIG_CMD_COMXTEST
#undef CONFIG_CMD_ECTEMP
#undef CONFIG_CMD_GSV
diff --git a/include/gpio.h b/include/gpio.h
index ac25ee8d39..bdedbf4bb7 100644
--- a/include/gpio.h
+++ b/include/gpio.h
@@ -28,6 +28,7 @@
#define GPIO_INT_F_LOW (1 << 11) /* Interrupt on low level */
#define GPIO_INT_F_HIGH (1 << 12) /* Interrupt on high level */
#define GPIO_DEFAULT (1 << 13) /* Don't set up on boot */
+#define GPIO_INT_DSLEEP (1 << 14) /* Interrupt in deep sleep */
/* Common flag combinations */
#define GPIO_OUT_LOW (GPIO_OUTPUT | GPIO_LOW)
@@ -42,6 +43,7 @@
#define GPIO_INT_EDGE (GPIO_INT_RISING | GPIO_INT_FALLING | GPIO_INT_BOTH)
#define GPIO_INT_LEVEL (GPIO_INT_LOW | GPIO_INT_HIGH)
#define GPIO_INT_ANY (GPIO_INT_EDGE | GPIO_INT_LEVEL)
+#define GPIO_INT_BOTH_DSLEEP (GPIO_INT_BOTH | GPIO_INT_DSLEEP)
/* GPIO signal definition structure, for use by board.c */
struct gpio_info {