diff options
author | Tom Hughes <tomhughes@chromium.org> | 2022-01-07 11:30:28 -0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2022-01-22 00:31:16 +0000 |
commit | 3b7724a3d3b6612a7d0f17ca70a47b6ff2f5bcfe (patch) | |
tree | f9629a5e4bd8408ab32e1ba62ae07d90825e776f | |
parent | f6cf98cdf979fb6d291fa021ed84f1958569a335 (diff) | |
download | chrome-ec-3b7724a3d3b6612a7d0f17ca70a47b6ff2f5bcfe.tar.gz |
tree: Delete chip/lm4 and board/bds
While working on https://crrev.com/c/3373621, I noticed that either the
comment or code was wrong in chip/lm4/clock.c.
chip/lm4 is only used by the "bds" board, which doesn't appear to be
used anymore, so just delete it.
BRANCH=none
BUG=b:200828093
TEST=make buildall -j
Cq-Depend: chromium:3378222
Signed-off-by: Tom Hughes <tomhughes@chromium.org>
Change-Id: I444a9a6e2c853dc4f9f3d799182daaeb110b1277
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3373622
Reviewed-by: Jack Rosenthal <jrosenth@chromium.org>
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | board/bds/board.c | 44 | ||||
-rw-r--r-- | board/bds/board.h | 55 | ||||
-rw-r--r-- | board/bds/build.mk | 12 | ||||
-rw-r--r-- | board/bds/ec.tasklist | 12 | ||||
-rw-r--r-- | board/bds/gpio.inc | 25 | ||||
-rw-r--r-- | chip/lm4/adc.c | 273 | ||||
-rw-r--r-- | chip/lm4/adc_chip.h | 44 | ||||
-rw-r--r-- | chip/lm4/build.mk | 31 | ||||
-rw-r--r-- | chip/lm4/chip_temp_sensor.c | 29 | ||||
-rw-r--r-- | chip/lm4/clock.c | 753 | ||||
-rw-r--r-- | chip/lm4/config_chip.h | 108 | ||||
-rw-r--r-- | chip/lm4/eeprom.c | 268 | ||||
-rw-r--r-- | chip/lm4/fan.c | 192 | ||||
-rw-r--r-- | chip/lm4/flash.c | 293 | ||||
-rw-r--r-- | chip/lm4/gpio.c | 385 | ||||
-rw-r--r-- | chip/lm4/hwtimer.c | 108 | ||||
-rw-r--r-- | chip/lm4/i2c.c | 413 | ||||
-rw-r--r-- | chip/lm4/keyboard_raw.c | 119 | ||||
-rw-r--r-- | chip/lm4/lpc.c | 835 | ||||
-rw-r--r-- | chip/lm4/peci.c | 152 | ||||
-rw-r--r-- | chip/lm4/pwm.c | 70 | ||||
-rw-r--r-- | chip/lm4/pwm_chip.h | 21 | ||||
-rw-r--r-- | chip/lm4/registers.h | 601 | ||||
-rw-r--r-- | chip/lm4/spi.c | 179 | ||||
-rw-r--r-- | chip/lm4/system.c | 776 | ||||
-rw-r--r-- | chip/lm4/uart.c | 352 | ||||
-rw-r--r-- | chip/lm4/watchdog.c | 120 |
28 files changed, 1 insertions, 6271 deletions
@@ -13,7 +13,7 @@ # This is used to exclude build targets that depend on sanitizers such as # fuzzers on architectures that don't support sanitizers yet (e.g. arm). ARCH?=amd64 -BOARD ?= bds +BOARD ?= elm # Directory where the board is configured (includes /$(BOARD) at the end) BDIR:=$(wildcard board/$(BOARD)) diff --git a/board/bds/board.c b/board/bds/board.c deleted file mode 100644 index aedc570d51..0000000000 --- a/board/bds/board.c +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 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. - */ -/* Stellaris EKB-LM4F-EAC board-specific configuration */ - -#include "adc.h" -#include "gpio.h" -#include "i2c.h" -#include "registers.h" -#include "util.h" - -/* ADC channels. Must be in the exactly same order as in enum adc_channel. */ -const struct adc_t adc_channels[] = { - /* EC internal temperature is calculated by - * 273 + (295 - 450 * ADC_VALUE / ADC_READ_MAX) / 2 - * = -225 * ADC_VALUE / ADC_READ_MAX + 420.5 - */ - {"ECTemp", LM4_ADC_SEQ0, -225, ADC_READ_MAX, 420, - LM4_AIN_NONE, 0x0e /* TS0 | IE0 | END0 */, 0, 0}, - - /* Charger current is mapped from 0~4000mA to 0~1.6V. - * And ADC maps 0~3.3V to ADC_READ_MAX. - * - * Note that on BDS, this is really just the turn pot on the Badger - * board, but that's good enough for debugging the ADC. - */ - {"BDSPot", LM4_ADC_SEQ1, 33 * 4000, ADC_READ_MAX * 16, 0, - LM4_AIN(0), 0x06 /* IE0 | END0 */, LM4_GPIO_E, (1<<3)}, -}; -BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT); - - -/* I2C ports */ -const struct i2c_port_t i2c_ports[] = { - { - .name = "lightbar", - .port = 5, - .kbps = 400 - }, -}; -const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports); - -#include "gpio_list.h" diff --git a/board/bds/board.h b/board/bds/board.h deleted file mode 100644 index 21dc2ad598..0000000000 --- a/board/bds/board.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright 2013 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. - */ - -/* Stellaris EKB-LM4F-EAC board configuration */ - -#ifndef __CROS_EC_BOARD_H -#define __CROS_EC_BOARD_H - -/* Optional features */ -#define CONFIG_SYSTEM_UNLOCKED /* Allow dangerous commands */ -#define CONFIG_I2C -#define CONFIG_I2C_CONTROLLER - -/* LM4 modules we don't use on link but still want to keep compiling */ -#define CONFIG_EEPROM -#define CONFIG_PSTORE - -/* Modules we want to exclude */ -#undef CONFIG_LID_SWITCH -#undef CONFIG_HOST_INTERFACE_LPC -#undef CONFIG_PECI -#undef CONFIG_SWITCH - -/* Write protect is active high */ -#define CONFIG_WP_ACTIVE_HIGH - -#ifndef __ASSEMBLER__ - -enum adc_channel { - ADC_CH_EC_TEMP = 0, /* EC internal die temperature in degrees K. */ - ADC_CH_BDS_POT, /* BDS pot input. */ - ADC_CH_COUNT -}; - -enum pwm_channel { - PWM_CH_COUNT -}; - -/* I2C ports */ -#define I2C_PORT_LIGHTBAR 5 /* Port 5 / PA6:7 on link, but PG6:7 on badger */ - -/* Second UART port */ -#define CONFIG_UART_HOST 1 - -#include "gpio_signal.h" - -/* EEPROM blocks */ -#define EEPROM_BLOCK_START_PSTORE 16 /* Host persistent storage */ -#define EEPROM_BLOCK_COUNT_PSTORE 16 - -#endif /* !__ASSEMBLER__ */ - -#endif /* __CROS_EC_BOARD_H */ diff --git a/board/bds/build.mk b/board/bds/build.mk deleted file mode 100644 index e3e91f0bb2..0000000000 --- a/board/bds/build.mk +++ /dev/null @@ -1,12 +0,0 @@ -# -*- makefile -*- -# Copyright 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. -# -# Board specific files build -# - -# the IC is TI Stellaris LM4 -CHIP:=lm4 - -board-y=board.o diff --git a/board/bds/ec.tasklist b/board/bds/ec.tasklist deleted file mode 100644 index 7329da7d2d..0000000000 --- a/board/bds/ec.tasklist +++ /dev/null @@ -1,12 +0,0 @@ -/* Copyright 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. - */ - -/** - * See CONFIG_TASK_LIST in config.h for details. - */ -#define CONFIG_TASK_LIST \ - TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \ - TASK_NOTEST(LIGHTBAR, lightbar_task, NULL, TASK_STACK_SIZE) \ - TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE) diff --git a/board/bds/gpio.inc b/board/bds/gpio.inc deleted file mode 100644 index 374894f932..0000000000 --- a/board/bds/gpio.inc +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- mode:c -*- - * - * Copyright 2014 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. - */ - -/* Declare symbolic names for all the GPIOs that we care about. - * Note: Those with interrupt handlers must be declared first. */ - -/* Recovery signal from DOWN button */ -GPIO(RECOVERY_L, PIN(D, 1), GPIO_PULL_UP) -GPIO(DEBUG_LED, PIN(A, 7), GPIO_OUT_LOW) - -/* - * Signals which aren't implemented on BDS but we'll emulate anyway, to - * make it more convenient to debug other code. - */ -UNIMPLEMENTED(WP) /* Write protect input */ -UNIMPLEMENTED(ENTERING_RW) /* EC entering RW code */ - -ALTERNATE(PIN_MASK(A, 0x03), 1, MODULE_UART, 0) /* UART0 */ -ALTERNATE(PIN_MASK(G, 0x40), 3, MODULE_I2C, 0) /* I2C5 SCL */ -ALTERNATE(PIN_MASK(G, 0x80), 3, GPIO_OPEN_DRAIN, 0) /* I2C5 SDA */ -ALTERNATE(PIN_MASK(B, 0x03), 1, MODULE_UART, 0) /* UART1 */ diff --git a/chip/lm4/adc.c b/chip/lm4/adc.c deleted file mode 100644 index 9c52cbbdd7..0000000000 --- a/chip/lm4/adc.c +++ /dev/null @@ -1,273 +0,0 @@ -/* Copyright 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. - */ - -/* LM4-specific ADC module for Chrome EC */ - -#include "adc.h" -#include "atomic.h" -#include "clock.h" -#include "console.h" -#include "common.h" -#include "gpio.h" -#include "hooks.h" -#include "registers.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -/* Maximum time we allow for an ADC conversion */ -#define ADC_TIMEOUT_US SECOND - -static volatile task_id_t task_waiting_on_ss[LM4_ADC_SEQ_COUNT]; - -static void configure_gpio(void) -{ - int i, port, mask; - - /* Use analog function for AIN */ - for (i = 0; i < ADC_CH_COUNT; ++i) { - if (adc_channels[i].gpio_mask) { - mask = adc_channels[i].gpio_mask; - port = adc_channels[i].gpio_port; - LM4_GPIO_DEN(port) &= ~mask; - LM4_GPIO_AMSEL(port) |= mask; - } - } -} - -/** - * Flush an ADC sequencer and initiate a read. - * - * @param seq Sequencer to read - * @return Raw ADC value. - */ -static int flush_and_read(enum lm4_adc_sequencer seq) -{ - /* - * This is currently simple because we can dedicate a sequencer to each - * ADC channel. If we have enough channels that's no longer possible, - * this code will need to become more complex. For example, we could: - * - * 1) Read them all using a timer interrupt, and then return the most - * recent value? This is lowest-latency for the caller, but won't - * return accurate data if read frequently. - * - * 2) Reserve SS3 for reading a single value, and configure it on each - * read? Needs mutex if we could have multiple callers; doesn't matter - * if just used for debugging. - * - * 3) Both? - */ - volatile uint32_t scratch __attribute__((unused)); - int event; - - /* Empty the FIFO of any previous results */ - while (!(LM4_ADC_SSFSTAT(seq) & 0x100)) - scratch = LM4_ADC_SSFIFO(seq); - - /* - * This assumes we don't have multiple tasks accessing the same - * sequencer. Add mutex lock if needed. - */ - task_waiting_on_ss[seq] = task_get_current(); - - /* Clear the interrupt status */ - LM4_ADC_ADCISC |= 0x01 << seq; - - /* Enable interrupt */ - LM4_ADC_ADCIM |= 0x01 << seq; - - /* Initiate sample sequence */ - LM4_ADC_ADCPSSI |= 0x01 << seq; - - /* Wait for interrupt */ - event = task_wait_event_mask(TASK_EVENT_ADC_DONE, ADC_TIMEOUT_US); - - /* Disable interrupt */ - LM4_ADC_ADCIM &= ~(0x01 << seq); - - task_waiting_on_ss[seq] = TASK_ID_INVALID; - - if (!(event & TASK_EVENT_ADC_DONE)) - return ADC_READ_ERROR; - - /* Read the FIFO and convert to temperature */ - return LM4_ADC_SSFIFO(seq); -} - -/** - * Configure an ADC sequencer to be dedicated for an ADC input. - * - * @param seq Sequencer to configure - * @param ain_id ADC input to use - * @param ssctl Value for sampler sequencer control register - * - */ -static void adc_configure(const struct adc_t *adc) -{ - const enum lm4_adc_sequencer seq = adc->sequencer; - - /* Configure sample sequencer */ - LM4_ADC_ADCACTSS &= ~(0x01 << seq); - - /* Trigger sequencer by processor request */ - LM4_ADC_ADCEMUX = (LM4_ADC_ADCEMUX & ~(0xf << (seq * 4))) | 0x00; - - /* Sample internal temp sensor */ - if (adc->channel == LM4_AIN_NONE) { - LM4_ADC_SSMUX(seq) = 0x00; - LM4_ADC_SSEMUX(seq) = 0x00; - } else { - LM4_ADC_SSMUX(seq) = adc->channel & 0xf; - LM4_ADC_SSEMUX(seq) = adc->channel >> 4; - } - LM4_ADC_SSCTL(seq) = adc->flag; - - /* Enable sample sequencer */ - LM4_ADC_ADCACTSS |= 0x01 << seq; -} - -int adc_read_channel(enum adc_channel ch) -{ - const struct adc_t *adc = adc_channels + ch; - static uint32_t ch_busy_mask; - static struct mutex adc_clock; - int rv; - - /* - * TODO(crbug.com/314121): Generalize ADC reads such that any task can - * trigger a read of any channel. - */ - - /* - * Enable ADC clock and set a bit in ch_busy_mask to signify that this - * channel is busy. Note, this function may be called from multiple - * tasks, but each channel may be read by only one task. If assert - * fails, then it means multiple tasks are trying to read same channel. - */ - mutex_lock(&adc_clock); - ASSERT(!(ch_busy_mask & (1UL << ch))); - clock_enable_peripheral(CGC_OFFSET_ADC, 0x1, - CGC_MODE_RUN | CGC_MODE_SLEEP); - ch_busy_mask |= (1UL << ch); - mutex_unlock(&adc_clock); - - rv = flush_and_read(adc->sequencer); - - /* - * If no ADC channels are busy, then disable ADC clock to conserve - * power. - */ - mutex_lock(&adc_clock); - ch_busy_mask &= ~(1UL << ch); - if (!ch_busy_mask) - clock_disable_peripheral(CGC_OFFSET_ADC, 0x1, - CGC_MODE_RUN | CGC_MODE_SLEEP); - mutex_unlock(&adc_clock); - - if (rv == ADC_READ_ERROR) - return ADC_READ_ERROR; - - return rv * adc->factor_mul / adc->factor_div + adc->shift; -} - -/*****************************************************************************/ -/* Interrupt handlers */ - -/** - * Handle an interrupt on the specified sample sequencer. - */ -static void handle_interrupt(int ss) -{ - int id = task_waiting_on_ss[ss]; - - /* Clear the interrupt status */ - LM4_ADC_ADCISC = (0x1 << ss); - - /* Wake up the task which was waiting on the interrupt, if any */ - if (id != TASK_ID_INVALID) - task_set_event(id, TASK_EVENT_ADC_DONE); -} - -static void ss0_interrupt(void) { handle_interrupt(0); } -static void ss1_interrupt(void) { handle_interrupt(1); } -static void ss2_interrupt(void) { handle_interrupt(2); } -static void ss3_interrupt(void) { handle_interrupt(3); } - -DECLARE_IRQ(LM4_IRQ_ADC0_SS0, ss0_interrupt, 2); -DECLARE_IRQ(LM4_IRQ_ADC0_SS1, ss1_interrupt, 2); -DECLARE_IRQ(LM4_IRQ_ADC0_SS2, ss2_interrupt, 2); -DECLARE_IRQ(LM4_IRQ_ADC0_SS3, ss3_interrupt, 2); - -/*****************************************************************************/ -/* Console commands */ - -#ifdef CONFIG_CMD_ECTEMP -static int command_ectemp(int argc, char **argv) -{ - int t = adc_read_channel(ADC_CH_EC_TEMP); - ccprintf("EC temperature is %d K = %d C\n", t, K_TO_C(t)); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(ectemp, command_ectemp, - NULL, - "Print EC temperature"); -#endif - -/*****************************************************************************/ -/* Initialization */ - -static void adc_init(void) -{ - int i; - - /* Configure GPIOs */ - configure_gpio(); - - /* - * Temporarily enable the PLL when turning on the clock to the ADC - * module, to work around chip errata (10.4). No need to notify - * other modules; the PLL isn't enabled long enough to matter. - */ - clock_enable_pll(1, 0); - - /* 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 - * VDDA and GNDA. - */ - LM4_ADC_ADCCTL = 0x01; - - /* Use internal oscillator */ - LM4_ADC_ADCCC = 0x1; - - /* Disable the PLL now that the ADC is using the internal oscillator */ - clock_enable_pll(0, 0); - - /* No tasks waiting yet */ - for (i = 0; i < LM4_ADC_SEQ_COUNT; i++) - task_waiting_on_ss[i] = TASK_ID_INVALID; - - /* Enable IRQs */ - task_enable_irq(LM4_IRQ_ADC0_SS0); - task_enable_irq(LM4_IRQ_ADC0_SS1); - task_enable_irq(LM4_IRQ_ADC0_SS2); - task_enable_irq(LM4_IRQ_ADC0_SS3); - - /* 2**6 = 64x oversampling */ - LM4_ADC_ADCSAC = 6; - - /* Initialize ADC sequencer */ - for (i = 0; i < ADC_CH_COUNT; ++i) - adc_configure(adc_channels + i); - - /* Disable ADC0 module until it is needed to conserve power. */ - clock_disable_peripheral(CGC_OFFSET_ADC, 0x1, - CGC_MODE_RUN | CGC_MODE_SLEEP); -} -DECLARE_HOOK(HOOK_INIT, adc_init, HOOK_PRIO_INIT_ADC); diff --git a/chip/lm4/adc_chip.h b/chip/lm4/adc_chip.h deleted file mode 100644 index a402c845a1..0000000000 --- a/chip/lm4/adc_chip.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 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. - */ - -/* LM4-specific ADC module for Chrome EC */ - -#ifndef __CROS_EC_ADC_CHIP_H -#define __CROS_EC_ADC_CHIP_H - -#include <stdint.h> - -enum lm4_adc_sequencer { - LM4_ADC_SEQ0 = 0, - LM4_ADC_SEQ1, - LM4_ADC_SEQ2, - LM4_ADC_SEQ3, - LM4_ADC_SEQ_COUNT -}; - -/* Data structure to define ADC channels. */ -struct adc_t { - const char *name; - enum lm4_adc_sequencer sequencer; - int factor_mul; - int factor_div; - int shift; - int channel; - int flag; - uint32_t gpio_port; - uint8_t gpio_mask; -}; - -/* Minimum and maximum values returned by raw ADC read. */ -#define ADC_READ_MIN 0 -#define ADC_READ_MAX 4095 - -/* Just plain id mapping for code readability */ -#define LM4_AIN(x) (x) - -/* Mock value for "channel" in adc_t if we don't have an external channel. */ -#define LM4_AIN_NONE (-1) - -#endif /* __CROS_EC_ADC_CHIP_H */ diff --git a/chip/lm4/build.mk b/chip/lm4/build.mk deleted file mode 100644 index c1d7787bf3..0000000000 --- a/chip/lm4/build.mk +++ /dev/null @@ -1,31 +0,0 @@ -# -*- makefile -*- -# Copyright 2013 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. -# -# LM4 chip specific files build -# - -# LM4 SoC has a Cortex-M4F ARM core -CORE:=cortex-m -# Allow the full Cortex-M4 instruction set -CFLAGS_CPU+=-march=armv7e-m -mcpu=cortex-m4 - -# Required chip modules -chip-y=clock.o gpio.o hwtimer.o system.o uart.o - -# Optional chip modules -chip-$(CONFIG_ADC)+=adc.o chip_temp_sensor.o -chip-$(CONFIG_EEPROM)+=eeprom.o -chip-$(CONFIG_FANS)+=fan.o -chip-$(CONFIG_FLASH_PHYSICAL)+=flash.o -chip-$(CONFIG_I2C)+=i2c.o -chip-$(CONFIG_HOST_INTERFACE_LPC)+=lpc.o -chip-$(CONFIG_PECI)+=peci.o -# pwm functions are implemented with the fan functions -chip-$(CONFIG_PWM)+=pwm.o fan.o -chip-$(CONFIG_SPI)+=spi.o -chip-$(CONFIG_WATCHDOG)+=watchdog.o -ifndef CONFIG_KEYBOARD_NOT_RAW -chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o -endif diff --git a/chip/lm4/chip_temp_sensor.c b/chip/lm4/chip_temp_sensor.c deleted file mode 100644 index 93b66f5f3f..0000000000 --- a/chip/lm4/chip_temp_sensor.c +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright 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. - */ - -/* Temperature sensor module for Chrome EC */ - -#include "adc.h" -#include "common.h" -#include "hooks.h" - -/* Initialize temperature reading to a valid value (27 C) */ -static int last_val = C_TO_K(27); - -static void chip_temp_sensor_poll(void) -{ - last_val = adc_read_channel(ADC_CH_EC_TEMP); -} -DECLARE_HOOK(HOOK_SECOND, chip_temp_sensor_poll, HOOK_PRIO_TEMP_SENSOR); - -int chip_temp_sensor_get_val(int idx, int *temp_ptr) -{ - if (last_val == ADC_READ_ERROR) - return EC_ERROR_UNKNOWN; - - *temp_ptr = last_val; - - return EC_SUCCESS; -} diff --git a/chip/lm4/clock.c b/chip/lm4/clock.c deleted file mode 100644 index 31ace04ce5..0000000000 --- a/chip/lm4/clock.c +++ /dev/null @@ -1,753 +0,0 @@ -/* Copyright 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 */ - -#include "clock.h" -#include "common.h" -#include "console.h" -#include "cpu.h" -#include "gpio.h" -#include "hooks.h" -#include "hwtimer.h" -#include "registers.h" -#include "system.h" -#include "task.h" -#include "timer.h" -#include "uart.h" -#include "util.h" -#include "watchdog.h" - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_CLOCK, outstr) -#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ## args) - -#define PLL_CLOCK 66666667 /* System clock = 200MHz PLL/3 = 66.667MHz */ - -#ifdef CONFIG_LOW_POWER_USE_LFIOSC -/* - * Length of time for the processor to wake up from deep sleep. Actual - * measurement gives anywhere up to 780us, depending on the mode it is coming - * out of. The datasheet gives a maximum of 846us, for coming out of deep - * sleep in our worst case deep sleep mode. - */ -#define DEEP_SLEEP_RECOVER_TIME_USEC 850 -#else -/* - * Length of time for the processor to wake up from deep sleep. Datasheet - * maximum is 145us, but in practice have seen as much as 336us. - */ -#define DEEP_SLEEP_RECOVER_TIME_USEC 400 -#endif - -/* Low power idle statistics */ -#ifdef CONFIG_LOW_POWER_IDLE -static int idle_sleep_cnt; -static int idle_dsleep_cnt; -static uint64_t idle_dsleep_time_us; -static int dsleep_recovery_margin_us = 1000000; - -/* - * Fixed amount of time to keep the console in use flag true after boot in - * order to give a permanent window in which the low speed clock is not used. - */ -#define CONSOLE_IN_USE_ON_BOOT_TIME (15*SECOND) - -static int console_in_use_timeout_sec = 60; -static timestamp_t console_expire_time; -#endif - -static int freq; - -/** - * Disable the PLL; run off internal oscillator. - */ -static void disable_pll(void) -{ - /* 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; - -#ifdef CONFIG_LOW_POWER_IDLE - /* - * If using the low power idle, then set the ACG bit, which specifies - * that the sleep and deep sleep modes are using their own clock gating - * registers SCGC and DCGS respectively instead of using the run mode - * clock gating registers RCGC. - */ - LM4_SYSTEM_RCC |= LM4_SYSTEM_RCC_ACG; -#endif - - LM4_SYSTEM_RCC2 &= ~LM4_SYSTEM_RCC2_USERCC2; - - freq = INTERNAL_CLOCK; -} - -/** - * Enable the PLL to run at full clock speed. - */ -static void enable_pll(void) -{ - /* Disable the PLL so we can reconfigure it */ - 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; - -#ifdef CONFIG_LOW_POWER_IDLE - /* - * If using the low power idle, then set the ACG bit, which specifies - * that the sleep and deep sleep modes are using their own clock gating - * registers SCGC and DCGS respectively instead of using the run mode - * clock gating registers RCGC. - */ - LM4_SYSTEM_RCC |= LM4_SYSTEM_RCC_ACG; -#endif - - /* 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; - freq = PLL_CLOCK; -} - -void clock_enable_pll(int enable, int notify) -{ - if (enable) - enable_pll(); - else - disable_pll(); - - /* Notify modules of frequency change */ - if (notify) - hook_notify(HOOK_FREQ_CHANGE); -} - -void clock_wait_cycles(uint32_t cycles) -{ - asm volatile("1: subs %0, #1\n" - " bne 1b\n" : "+r"(cycles)); -} - -int clock_get_freq(void) -{ - return freq; -} - -void clock_init(void) -{ -#ifdef BOARD_BDS - /* - * Perform an auto calibration of the internal oscillator using the - * 32.768KHz hibernate clock, unless we've already done so. This is - * only necessary on A2 silicon as on BDS; A3 silicon is all - * 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)) - ; - } -#else - /* - * 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 - - /* Make sure PLL is disabled */ - 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; -} - -/* - * The low power idle task does not support using the EEPROM, - * because it is dangerous to go to deep sleep while EEPROM - * transaction is in progress. To fix, LM4_EEPROM_EEDONE, should - * be checked before going in to deep sleep. - */ -#if defined(CONFIG_LOW_POWER_IDLE) && defined(CONFIG_EEPROM) -#error "Low power idle mode does not support use of EEPROM" -#endif - -#ifdef CONFIG_LOW_POWER_IDLE - -void clock_refresh_console_in_use(void) -{ - disable_sleep(SLEEP_MASK_CONSOLE); - - /* Set console in use expire time. */ - console_expire_time = get_time(); - console_expire_time.val += console_in_use_timeout_sec * SECOND; - -} - -/* Low power idle task. Executed when no tasks are ready to be scheduled. */ -void __idle(void) -{ - timestamp_t t0, t1, rtc_t0, rtc_t1; - int next_delay = 0; - int time_for_dsleep, margin_us; - int use_low_speed_clock; - - /* Enable the hibernate IRQ used to wake up from deep sleep */ - system_enable_hib_interrupt(); - - /* Set SRAM and flash power management to 'low power' in deep sleep. */ - LM4_SYSTEM_DSLPPWRCFG = 0x23; - - /* Enable JTAG interrupt which will notify us when JTAG is in use. */ - gpio_enable_interrupt(GPIO_JTAG_TCK); - - /* - * Initialize console in use to true and specify the console expire - * time in order to give a fixed window on boot in which the low speed - * clock will not be used in idle. - */ - disable_sleep(SLEEP_MASK_CONSOLE); - console_expire_time.val = get_time().val + CONSOLE_IN_USE_ON_BOOT_TIME; - - /* - * Print when the idle task starts. This is the lowest priority task, - * so this only starts once all other tasks have gotten a chance to do - * their task inits and have gone to sleep. - */ - CPRINTS("low power idle task started"); - - while (1) { - /* - * Disable interrupts before going to deep sleep in order to - * calculate the appropriate time to wake up. Note: the wfi - * instruction waits until an interrupt is pending, so it - * will still wake up even with interrupts disabled. - */ - interrupt_disable(); - - t0 = get_time(); - next_delay = __hw_clock_event_get() - t0.le.lo; - - /* Do we have enough time before next event to deep sleep. */ - time_for_dsleep = next_delay > (DEEP_SLEEP_RECOVER_TIME_USEC + - HIB_SET_RTC_MATCH_DELAY_USEC); - - if (DEEP_SLEEP_ALLOWED && time_for_dsleep) { - /* Deep-sleep in STOP mode. */ - idle_dsleep_cnt++; - - /* Check if the console use has expired. */ - if ((sleep_mask & SLEEP_MASK_CONSOLE) && - t0.val > console_expire_time.val) { - /* Enable low speed deep sleep. */ - enable_sleep(SLEEP_MASK_CONSOLE); - - /* - * Wait one clock before checking if low speed - * deep sleep is allowed to give time for - * sleep mask to update. - */ - clock_wait_cycles(1); - - if (LOW_SPEED_DEEP_SLEEP_ALLOWED) - CPRINTS("Disabling console in " - "deep sleep"); - } - - /* - * Determine if we should use a lower clock speed or - * keep the same (16MHz) clock in deep sleep. Use the - * lower speed only if the sleep mask specifies that low - * speed sleep is allowed, the console UART TX is not - * busy, and the console UART buffer is empty. - */ - use_low_speed_clock = LOW_SPEED_DEEP_SLEEP_ALLOWED && - !uart_tx_in_progress() && uart_buffer_empty(); - -#ifdef CONFIG_LOW_POWER_USE_LFIOSC - /* Set the deep sleep clock register. Use either the - * normal PIOSC (16MHz) or the LFIOSC (32kHz). */ - LM4_SYSTEM_DSLPCLKCFG = use_low_speed_clock ? - 0x32 : 0x10; -#else - /* - * Set the deep sleep clock register. Use either the - * PIOSC with no divider (16MHz) or the PIOSC with - * a /64 divider (250kHz). - */ - LM4_SYSTEM_DSLPCLKCFG = use_low_speed_clock ? - 0x1f800010 : 0x10; -#endif - - /* - * If using low speed clock, disable console. - * This will also convert the console RX pin to a GPIO - * and set an edge interrupt to wake us from deep sleep - * if any action occurs on console. - */ - if (use_low_speed_clock) - uart_enter_dsleep(); - - /* Set deep sleep bit. */ - CPU_SCB_SYSCTRL |= 0x4; - - /* Record real time before sleeping. */ - rtc_t0 = system_get_rtc(); - - /* - * Set RTC interrupt in time to wake up before - * next event. - */ - system_set_rtc_alarm(0, next_delay - - DEEP_SLEEP_RECOVER_TIME_USEC); - - /* Wait for interrupt: goes into deep sleep. */ - asm("wfi"); - - /* Clear deep sleep bit. */ - CPU_SCB_SYSCTRL &= ~0x4; - - /* Disable and clear RTC interrupt. */ - system_reset_rtc_alarm(); - - /* Fast forward timer according to RTC counter. */ - rtc_t1 = system_get_rtc(); - t1.val = t0.val + (rtc_t1.val - rtc_t0.val); - force_time(t1); - - /* If using low speed clock, re-enable the console. */ - if (use_low_speed_clock) - uart_exit_dsleep(); - - /* Record time spent in deep sleep. */ - idle_dsleep_time_us += (rtc_t1.val - rtc_t0.val); - - /* Calculate how close we were to missing deadline */ - margin_us = next_delay - (int)(rtc_t1.val - rtc_t0.val); - if (margin_us < 0) - CPRINTS("overslept by %dus", -margin_us); - - /* Record the closest to missing a deadline. */ - if (margin_us < dsleep_recovery_margin_us) - dsleep_recovery_margin_us = margin_us; - } else { - idle_sleep_cnt++; - - /* Normal idle : only CPU clock stopped. */ - asm("wfi"); - } - interrupt_enable(); - } -} -#endif /* CONFIG_LOW_POWER_IDLE */ - -/*****************************************************************************/ -/* Console commands */ - -#ifdef CONFIG_CMD_SLEEP -/** - * Measure baseline for power consumption. - * - * Levels : - * 0 : CPU running in tight loop - * 1 : CPU running in tight loop but peripherals gated - * 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 - * - * Clocks : - * 0 : No change - * 1 : 16MHz - * 2 : 1 MHz - * 3 : 30kHz - * - * SRAM Power Management: - * 0 : Active - * 1 : Standby - * 3 : Low Power - * - * Flash Power Management: - * 0 : Active - * 2 : Low Power - */ -static int command_sleep(int argc, char **argv) -{ - int level = 0; - int clock = 0; - int sram_pm = 0; - int flash_pm = 0; - uint32_t uartibrd = 0; - uint32_t uartfbrd = 0; - - if (argc >= 2) - level = strtoi(argv[1], NULL, 10); - if (argc >= 3) - clock = strtoi(argv[2], NULL, 10); - if (argc >= 4) - sram_pm = strtoi(argv[3], NULL, 10); - if (argc >= 5) - flash_pm = strtoi(argv[4], NULL, 10); - -#ifdef BOARD_BDS - /* Remove LED current sink. */ - gpio_set_level(GPIO_DEBUG_LED, 0); -#endif - - ccprintf("Sleep : level %d, clock %d, sram pm %d, flash_pm %d...\n", - level, clock, sram_pm, flash_pm); - cflush(); - - /* Set clock speed. */ - if (clock) { - /* Use ROM code function to set the clock */ - void **func_table = (void **)*(uint32_t *)0x01000044; - void (*rom_clock_set)(uint32_t rcc) = func_table[23]; - - /* Disable interrupts. */ - interrupt_disable(); - - switch (clock) { - case 1: /* 16MHz IOSC */ - uartibrd = 17; - uartfbrd = 23; - rom_clock_set(0x00000d51); - break; - case 2: /* 1MHz IOSC */ - uartibrd = 1; - uartfbrd = 5; - rom_clock_set(0x07C00d51); - break; - case 3: /* 30 kHz */ - uartibrd = 0; - uartfbrd = 0; - rom_clock_set(0x00000d71); - break; - } - - /* - * TODO(crosbug.com/p/23795): move this to the UART module; - * ugly to have UARTisms here. Also note this only fixes - * UART0, not UART1. Should just be able to trigger - * HOOK_FREQ_CHANGE and have that take care of it. - */ - if (uartfbrd) { - /* Disable the port via UARTCTL and add HSE. */ - LM4_UART_CTL(0) = 0x0320; - /* Set the baud rate divisor. */ - LM4_UART_IBRD(0) = uartibrd; - LM4_UART_FBRD(0) = uartfbrd; - /* Poke UARTLCRH to make the new divisor take effect. */ - LM4_UART_LCRH(0) = LM4_UART_LCRH(0); - /* Enable the port. */ - LM4_UART_CTL(0) |= 0x0001; - } - interrupt_enable(); - } - - if (uartfbrd) { - ccprintf("We are still alive. RCC=%08x\n", LM4_SYSTEM_RCC); - cflush(); - } - - /* Enable interrupts. */ - interrupt_disable(); - - /* gate peripheral clocks */ - if (level & 1) { - clock_disable_peripheral(CGC_OFFSET_WD, 0xffffffff, - CGC_MODE_ALL); - 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_HIB, 0xffffffff, - CGC_MODE_ALL); - clock_disable_peripheral(CGC_OFFSET_UART, 0xffffffff, - CGC_MODE_ALL); - clock_disable_peripheral(CGC_OFFSET_SSI, 0xffffffff, - CGC_MODE_ALL); - clock_disable_peripheral(CGC_OFFSET_I2C, 0xffffffff, - CGC_MODE_ALL); - clock_disable_peripheral(CGC_OFFSET_ADC, 0xffffffff, - CGC_MODE_ALL); - clock_disable_peripheral(CGC_OFFSET_LPC, 0xffffffff, - CGC_MODE_ALL); - clock_disable_peripheral(CGC_OFFSET_PECI, 0xffffffff, - CGC_MODE_ALL); - clock_disable_peripheral(CGC_OFFSET_FAN, 0xffffffff, - CGC_MODE_ALL); - clock_disable_peripheral(CGC_OFFSET_EEPROM, 0xffffffff, - CGC_MODE_ALL); - clock_disable_peripheral(CGC_OFFSET_WTIMER, 0xffffffff, - CGC_MODE_ALL); - } - - /* Set deep sleep bit. */ - if (level >= 4) - CPU_SCB_SYSCTRL |= 0x4; - - /* Set SRAM and flash PM for sleep and deep sleep. */ - LM4_SYSTEM_SLPPWRCFG = (flash_pm << 4) | sram_pm; - LM4_SYSTEM_DSLPPWRCFG = (flash_pm << 4) | sram_pm; - - /* Go to low power mode (forever ...) */ - if (level > 1) - while (1) { - asm("wfi"); - watchdog_reload(); - } - else - while (1) - watchdog_reload(); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(sleep, command_sleep, - "[level [clock] [sram pm] [flash pm]]", - "Drop into sleep"); -#endif /* CONFIG_CMD_SLEEP */ - -#ifdef CONFIG_CMD_PLL - -static int command_pll(int argc, char **argv) -{ - int v; - - /* Toggle the PLL */ - if (argc > 1) { - if (parse_bool(argv[1], &v)) { - clock_enable_pll(v, 1); - } else { - /* Disable PLL and set extra divider */ - char *e; - v = strtoi(argv[1], &e, 10); - if (*e) - return EC_ERROR_PARAM1; - - LM4_SYSTEM_RCC = LM4_SYSTEM_RCC_SYSDIV(v - 1) | - LM4_SYSTEM_RCC_BYPASS | - LM4_SYSTEM_RCC_PWRDN | - LM4_SYSTEM_RCC_OSCSRC(1) | - LM4_SYSTEM_RCC_MOSCDIS; - - freq = INTERNAL_CLOCK / v; - - /* Notify modules of frequency change */ - hook_notify(HOOK_FREQ_CHANGE); - } - } - - /* Print current PLL state */ - ccprintf("RCC: 0x%08x\n", LM4_SYSTEM_RCC); - ccprintf("RCC2: 0x%08x\n", LM4_SYSTEM_RCC2); - ccprintf("PLLSTAT: 0x%08x\n", LM4_SYSTEM_PLLSTAT); - ccprintf("Clock: %d Hz\n", clock_get_freq()); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(pll, command_pll, - "[ on | off | <div> ]", - "Get/set PLL state"); - -#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"); -#endif /* CONFIG_CMD_CLOCKGATES */ - -#ifdef CONFIG_LOW_POWER_IDLE -/** - * Print low power idle statistics - */ -static int command_idle_stats(int argc, char **argv) -{ - timestamp_t ts = get_time(); - - ccprintf("Num idle calls that sleep: %d\n", idle_sleep_cnt); - ccprintf("Num idle calls that deep-sleep: %d\n", idle_dsleep_cnt); - ccprintf("Time spent in deep-sleep: %.6llds\n", - idle_dsleep_time_us); - ccprintf("Total time on: %.6llds\n", ts.val); - ccprintf("Deep-sleep closest to wake deadline: %dus\n", - dsleep_recovery_margin_us); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(idlestats, command_idle_stats, - "", - "Print last idle stats"); - -/** - * Configure deep sleep clock settings. - */ -static int command_dsleep(int argc, char **argv) -{ - int v; - - if (argc > 1) { - if (parse_bool(argv[1], &v)) { - /* - * Force deep sleep not to use low speed clock or - * allow it to use the low speed clock. - */ - if (v) - disable_sleep(SLEEP_MASK_FORCE_NO_LOW_SPEED); - else - enable_sleep(SLEEP_MASK_FORCE_NO_LOW_SPEED); - } else { - /* Set console in use timeout. */ - char *e; - v = strtoi(argv[1], &e, 10); - if (*e) - return EC_ERROR_PARAM1; - - console_in_use_timeout_sec = v; - - /* Refresh console in use to use new timeout. */ - clock_refresh_console_in_use(); - } - } - - ccprintf("Sleep mask: %08x\n", sleep_mask); - ccprintf("Console in use timeout: %d sec\n", - console_in_use_timeout_sec); - ccprintf("DSLPCLKCFG register: 0x%08x\n", LM4_SYSTEM_DSLPCLKCFG); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(dsleep, command_dsleep, - "[ on | off | <timeout> sec]", - "Deep sleep clock settings:\nUse 'on' to force deep " - "sleep not to use low speed clock.\nUse 'off' to " - "allow deep sleep to auto-select using the low speed " - "clock.\n" - "Give a timeout value for the console in use timeout.\n" - "See also 'sleepmask'."); -#endif /* CONFIG_LOW_POWER_IDLE */ diff --git a/chip/lm4/config_chip.h b/chip/lm4/config_chip.h deleted file mode 100644 index 8e1ea51785..0000000000 --- a/chip/lm4/config_chip.h +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright 2013 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. - */ - -#ifndef __CROS_EC_CONFIG_CHIP_H -#define __CROS_EC_CONFIG_CHIP_H - -/* CPU core BFD configuration */ -#include "core/cortex-m/config_core.h" - -/* 16.000 MHz internal oscillator frequency (PIOSC) */ -#define INTERNAL_CLOCK 16000000 - -/* Number of IRQ vectors on the NVIC */ -#define CONFIG_IRQ_COUNT 132 - -/* Use a bigger console output buffer */ -#undef CONFIG_UART_TX_BUF_SIZE -#define CONFIG_UART_TX_BUF_SIZE 8192 - -/* Interval between HOOK_TICK notifications */ -#define HOOK_TICK_INTERVAL_MS 250 -#define HOOK_TICK_INTERVAL (HOOK_TICK_INTERVAL_MS * MSEC) - -/* Number of I2C ports */ -#define I2C_PORT_COUNT 6 - -/* - * Time it takes to set the RTC match register. This value is conservatively - * set based on measurements around 200us. - */ -#define HIB_SET_RTC_MATCH_DELAY_USEC 300 - -/****************************************************************************/ -/* Memory mapping */ - -#define CONFIG_RAM_BASE 0x20000000 -#define CONFIG_RAM_SIZE 0x00008000 - -/* System stack size */ -#define CONFIG_STACK_SIZE 4096 - -/* non-standard task stack sizes */ -#define IDLE_TASK_STACK_SIZE 512 -#define LARGER_TASK_STACK_SIZE 768 -#define SMALLER_TASK_STACK_SIZE 384 - -/* Default task stack size */ -#define TASK_STACK_SIZE 512 - -#define CONFIG_PROGRAM_MEMORY_BASE 0x00000000 -#define CONFIG_FLASH_BANK_SIZE 0x00000800 /* protect bank size */ -#define CONFIG_FLASH_ERASE_SIZE 0x00000400 /* erase bank size */ -#define CONFIG_FLASH_WRITE_SIZE 0x00000004 /* minimum write size */ - -/* Ideal flash write size fills the 32-entry flash write buffer */ -#define CONFIG_FLASH_WRITE_IDEAL_SIZE (32 * 4) - -/* This is the physical size of the flash on the chip. We'll reserve one bank - * in order to emulate per-bank write-protection UNTIL REBOOT. The hardware - * doesn't support a write-protect pin, and if we make the write-protection - * permanent, it can't be undone easily enough to support RMA. */ -#define CONFIG_FLASH_SIZE_BYTES 0x00040000 - -/****************************************************************************/ -/* Define our flash layout. */ - -/* Memory-mapped internal flash */ -#define CONFIG_INTERNAL_STORAGE -#define CONFIG_MAPPED_STORAGE - -/* Program is run directly from storage */ -#define CONFIG_MAPPED_STORAGE_BASE CONFIG_PROGRAM_MEMORY_BASE - -/* Compute the rest of the flash params from these */ -#include "config_std_internal_flash.h" - -/****************************************************************************/ -/* Lock the boot configuration to prevent brickage. */ - -/* - * No GPIO trigger for ROM bootloader. - * Keep JTAG debugging enabled. - * Use 0xA442 flash write key. - * Lock it this way. - */ -#define CONFIG_BOOTCFG_VALUE 0x7ffffffe - -/****************************************************************************/ -/* Customize the build */ - -/* Optional features present on this chip */ -#define CONFIG_ADC -#define CONFIG_HOSTCMD_ALIGNED -#define CONFIG_HOST_INTERFACE_LPC -#define CONFIG_PECI -#define CONFIG_RTC -#define CONFIG_SWITCH -#define CONFIG_MPU - -/* Chip needs to do custom pre-init */ -#define CONFIG_CHIP_PRE_INIT - -#define GPIO_PIN(port, index) GPIO_##port, BIT(index) -#define GPIO_PIN_MASK(p, m) .port = GPIO_##p, .mask = (m) - -#endif /* __CROS_EC_CONFIG_CHIP_H */ diff --git a/chip/lm4/eeprom.c b/chip/lm4/eeprom.c deleted file mode 100644 index 97fd3bdc24..0000000000 --- a/chip/lm4/eeprom.c +++ /dev/null @@ -1,268 +0,0 @@ -/* Copyright 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. - */ - -/* EEPROM module for Chrome EC */ - -#include "clock.h" -#include "console.h" -#include "eeprom.h" -#include "registers.h" -#include "timer.h" -#include "util.h" -#include "watchdog.h" - -/* Size of EEPROM block in bytes */ -#define EEPROM_BLOCK_SIZE 64 - -/* Count of EEPROM blocks */ -static int block_count; - -/* - * Wait for the current EEPROM operation to finish; all operations but write - * should normally finish in 4 system clocks, but worst case is up to - * 1800ms if the EEPROM needs to do an internal page erase/copy. We must - * spin-wait for this delay, because EEPROM operations will fail if the chip - * drops to sleep mode. - */ -static int wait_for_done(void) -{ - int j; - - for (j = 0; j < 20; j++) { /* 20 * 100 ms = 2000 ms */ - uint64_t tstop = get_time().val + 100 * MSEC; - while (get_time().val < tstop) { - if (!(LM4_EEPROM_EEDONE & 0x01)) - return EC_SUCCESS; - } - watchdog_reload(); - } - - return EC_ERROR_UNKNOWN; -} - - -int eeprom_get_block_count(void) -{ - return block_count; -} - - -int eeprom_get_block_size(void) -{ - return EEPROM_BLOCK_SIZE; -} - - -int eeprom_read(int block, int offset, int size, char *data) -{ - uint32_t *d = (uint32_t *)data; - int rv; - - if (block < 0 || block >= block_count || - offset < 0 || offset > EEPROM_BLOCK_SIZE || offset & 3 || - size < 0 || offset + size > EEPROM_BLOCK_SIZE || size & 3) - return EC_ERROR_UNKNOWN; - - rv = wait_for_done(); - if (rv) - return rv; - - LM4_EEPROM_EEBLOCK = block; - if (LM4_EEPROM_EEBLOCK != block) - return EC_ERROR_UNKNOWN; /* Error setting block */ - - LM4_EEPROM_EEOFFSET = offset >> 2; - - for (; size; size -= sizeof(uint32_t)) - *(d++) = LM4_EEPROM_EERDWRINC; - - return EC_SUCCESS; -} - - -int eeprom_write(int block, int offset, int size, const char *data) -{ - uint32_t *d = (uint32_t *)data; - int rv; - - if (block < 0 || block >= block_count || - offset < 0 || offset > EEPROM_BLOCK_SIZE || offset & 3 || - size < 0 || offset + size > EEPROM_BLOCK_SIZE || size & 3) - return EC_ERROR_UNKNOWN; - - rv = wait_for_done(); - if (rv) - return rv; - - LM4_EEPROM_EEBLOCK = block; - if (LM4_EEPROM_EEBLOCK != block) - return EC_ERROR_UNKNOWN; /* Error setting block */ - - LM4_EEPROM_EEOFFSET = offset >> 2; - - /* Write 32 bits at a time; wait for each write to complete */ - for (; size; size -= sizeof(uint32_t)) { - LM4_EEPROM_EERDWRINC = *(d++); - - rv = wait_for_done(); - if (rv) - return rv; - - if (LM4_EEPROM_EEDONE & 0x10) { - /* Failed due to write protect */ - return EC_ERROR_ACCESS_DENIED; - } else if (LM4_EEPROM_EEDONE & 0x100) { - /* Failed due to program voltage level */ - return EC_ERROR_UNKNOWN; - } - } - - return EC_SUCCESS; -} - - -int eeprom_hide(int block) -{ - /* Block 0 can't be hidden */ - if (block <= 0 || block >= block_count) - return EC_ERROR_UNKNOWN; - - LM4_EEPROM_EEHIDE |= 1 << block; - return EC_SUCCESS; -} - - -/*****************************************************************************/ -/* Console commands */ - -static int command_eeprom_info(int argc, char **argv) -{ - ccprintf("%d blocks @ %d bytes, hide=0x%08x\n", - eeprom_get_block_count(), eeprom_get_block_size(), - LM4_EEPROM_EEHIDE); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(eeinfo, command_eeprom_info, - NULL, - "Print EEPROM info"); - - -static int command_eeprom_read(int argc, char **argv) -{ - int block = 0; - int offset = 0; - char *e; - int rv; - uint32_t d; - - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - - block = strtoi(argv[1], &e, 0); - if (*e) - return EC_ERROR_PARAM1; - - if (argc > 2) { - offset = strtoi(argv[2], &e, 0); - if (*e) - return EC_ERROR_PARAM2; - } - - rv = eeprom_read(block, offset, sizeof(d), (char *)&d); - if (rv == EC_SUCCESS) - ccprintf("%d:%d = 0x%08x\n", block, offset, d); - return rv; -} -DECLARE_CONSOLE_COMMAND(eeread, command_eeprom_read, - "block [offset]", - "Read a word of EEPROM"); - - -static int command_eeprom_write(int argc, char **argv) -{ - int block = 0; - int offset = 0; - char *e; - uint32_t d; - - if (argc < 4) - return EC_ERROR_PARAM_COUNT; - - block = strtoi(argv[1], &e, 0); - if (*e) - return EC_ERROR_PARAM1; - offset = strtoi(argv[2], &e, 0); - if (*e) - return EC_ERROR_PARAM2; - d = strtoi(argv[3], &e, 0); - if (*e) - return EC_ERROR_PARAM3; - - ccprintf("Writing 0x%08x to %d:%d...\n", d, block, offset); - return eeprom_write(block, offset, sizeof(d), (char *)&d); -} -DECLARE_CONSOLE_COMMAND(eewrite, command_eeprom_write, - "block offset value", - "Write a word of EEPROM"); - - -#ifdef CONSOLE_COMMAND_EEHIDE -static int command_eeprom_hide(int argc, char **argv) -{ - int block = 0; - char *e; - - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - - block = strtoi(argv[1], &e, 0); - if (*e) - return EC_ERROR_PARAM1; - - ccprintf("Hiding block %d\n", block); - return eeprom_hide(block); -} -DECLARE_CONSOLE_COMMAND(eehide, command_eeprom_hide, - "block", - "Hide a block of EEPROM"); -#endif - - -/*****************************************************************************/ -/* Initialization */ - - -int eeprom_init(void) -{ - /* 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(); - - /* Store block count */ - block_count = LM4_EEPROM_EESIZE >> 16; - - /* - * Handle resetting the EEPROM module to clear state from a previous - * error condition. - */ - if (LM4_EEPROM_EESUPP & 0xc0) { - LM4_SYSTEM_SREEPROM = 1; - clock_wait_cycles(200); - LM4_SYSTEM_SREEPROM = 0; - - /* Wait again for internal init to finish */ - clock_wait_cycles(6); - wait_for_done(); - - /* Fail if error condition didn't clear */ - if (LM4_EEPROM_EESUPP & 0xc0) - return EC_ERROR_UNKNOWN; - } - - return EC_SUCCESS; -} diff --git a/chip/lm4/fan.c b/chip/lm4/fan.c deleted file mode 100644 index b09323a37b..0000000000 --- a/chip/lm4/fan.c +++ /dev/null @@ -1,192 +0,0 @@ -/* Copyright 2013 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. - */ - -/* LM4 fan control module. */ - -#include "clock.h" -#include "fan.h" -#include "gpio.h" -#include "hooks.h" -#include "registers.h" -#include "util.h" - -/* Maximum RPM for fan controller */ -#define MAX_RPM 0x1fff - -/* Maximum PWM for PWM controller */ -#define MAX_PWM 0x1ff - -/* - * Scaling factor for requested/actual RPM for CPU fan. We need this because - * the fan controller on Blizzard filters tach pulses that are less than 64 - * 15625Hz ticks apart, which works out to ~7000rpm on an unscaled fan. By - * telling the controller we actually have twice as many edges per revolution, - * the controller can handle fans that actually go twice as fast. See - * crosbug.com/p/7718. - */ -#define RPM_SCALE 2 - - -void fan_set_enabled(int ch, int enabled) -{ - if (enabled) - LM4_FAN_FANCTL |= BIT(ch); - else - LM4_FAN_FANCTL &= ~BIT(ch); -} - -int fan_get_enabled(int ch) -{ - return (LM4_FAN_FANCTL & BIT(ch)) ? 1 : 0; -} - -void fan_set_duty(int ch, int percent) -{ - int duty; - - if (percent < 0) - percent = 0; - else if (percent > 100) - percent = 100; - - duty = (MAX_PWM * percent + 50) / 100; - - /* Always enable the channel */ - fan_set_enabled(ch, 1); - - /* Set the duty cycle */ - LM4_FAN_FANCMD(ch) = duty << 16; -} - -int fan_get_duty(int ch) -{ - return ((LM4_FAN_FANCMD(ch) >> 16) * 100 + MAX_PWM / 2) / MAX_PWM; -} - -int fan_get_rpm_mode(int ch) -{ - return (LM4_FAN_FANCH(ch) & 0x0001) ? 0 : 1; -} - -void fan_set_rpm_mode(int ch, int rpm_mode) -{ - int was_enabled = fan_get_enabled(ch); - int was_rpm = fan_get_rpm_mode(ch); - - if (!was_rpm && rpm_mode) { - /* Enable RPM control */ - fan_set_enabled(ch, 0); - LM4_FAN_FANCH(ch) &= ~0x0001; - fan_set_enabled(ch, was_enabled); - } else if (was_rpm && !rpm_mode) { - /* Disable RPM mode */ - fan_set_enabled(ch, 0); - LM4_FAN_FANCH(ch) |= 0x0001; - fan_set_enabled(ch, was_enabled); - } -} - -int fan_get_rpm_actual(int ch) -{ - return (LM4_FAN_FANCST(ch) & MAX_RPM) * RPM_SCALE; -} - -int fan_get_rpm_target(int ch) -{ - return (LM4_FAN_FANCMD(ch) & MAX_RPM) * RPM_SCALE; -} - -test_mockable void fan_set_rpm_target(int ch, int rpm) -{ - /* Apply fan scaling */ - if (rpm > 0) - rpm /= RPM_SCALE; - - /* Treat out-of-range requests as requests for maximum fan speed */ - if (rpm < 0 || rpm > MAX_RPM) - rpm = MAX_RPM; - - LM4_FAN_FANCMD(ch) = rpm; -} - -/* The LM4 status is the original definition of enum fan_status */ -enum fan_status fan_get_status(int ch) -{ - return (LM4_FAN_FANSTS >> (2 * ch)) & 0x03; -} - -/** - * Return non-zero if fan is enabled but stalled. - */ -int fan_is_stalled(int ch) -{ - /* Must be enabled with non-zero target to stall */ - if (!fan_get_enabled(ch) || fan_get_rpm_target(ch) == 0) - return 0; - - /* Check for stall condition */ - return fan_get_status(ch) == FAN_STATUS_STOPPED; -} - -void fan_channel_setup(int ch, unsigned int flags) -{ - uint32_t init; - - if (flags & FAN_USE_RPM_MODE) - /* - * Configure automatic/feedback mode: - * 0x8000 = bit 15 = auto-restart - * 0x0000 = bit 14 = slow acceleration - * 0x0000 = bits 13:11 = no hysteresis - * 0x0000 = bits 10:8 = start period (2<<0) edges - * 0x0000 = bits 7:6 = no fast start - * 0x0020 = bits 5:4 = average 4 edges when - * calculating RPM - * 0x000c = bits 3:2 = 8 pulses per revolution - * (see note at top of file) - * 0x0000 = bit 0 = automatic control - */ - init = 0x802c; - else - /* - * Configure drive-only mode: - * 0x0000 = bit 15 = no auto-restart - * 0x0000 = bit 14 = slow acceleration - * 0x0000 = bits 13:11 = no hysteresis - * 0x0000 = bits 10:8 = start period (2<<0) edges - * 0x0000 = bits 7:6 = no fast start - * 0x0000 = bits 5:4 = no RPM averaging - * 0x0000 = bits 3:2 = 1 pulses per revolution - * 0x0001 = bit 0 = manual control - */ - init = 0x0001; - - if (flags & FAN_USE_FAST_START) - /* - * Configure fast-start mode - * 0x0000 = bits 10:8 = start period (2<<0) edges - * 0x0040 = bits 7:6 = fast start at 50% duty - */ - init |= 0x0040; - - LM4_FAN_FANCH(ch) = init; -} - -static void fan_init(void) -{ - -#ifdef CONFIG_FAN_DSLEEP - /* Enable the fan module and delay a few clocks */ - clock_enable_peripheral(CGC_OFFSET_FAN, 0x1, CGC_MODE_ALL); -#else - /* Enable the fan module and delay a few clocks */ - clock_enable_peripheral(CGC_OFFSET_FAN, 0x1, - CGC_MODE_RUN | CGC_MODE_SLEEP); -#endif - /* Disable all fans */ - LM4_FAN_FANCTL = 0; -} -/* Init before PWM */ -DECLARE_HOOK(HOOK_INIT, fan_init, HOOK_PRIO_INIT_FAN); diff --git a/chip/lm4/flash.c b/chip/lm4/flash.c deleted file mode 100644 index 5b61874984..0000000000 --- a/chip/lm4/flash.c +++ /dev/null @@ -1,293 +0,0 @@ -/* Copyright 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. - */ - -/* Flash memory module for Chrome EC */ - -#include "flash.h" -#include "registers.h" -#include "switch.h" -#include "system.h" -#include "timer.h" -#include "util.h" -#include "watchdog.h" - -#define FLASH_FWB_WORDS 32 -#define FLASH_FWB_BYTES (FLASH_FWB_WORDS * 4) - -#define BANK_SHIFT 5 /* bank registers have 32bits each, 2^32 */ -#define BANK_MASK (BIT(BANK_SHIFT) - 1) /* 5 bits */ -#define F_BANK(b) ((b) >> BANK_SHIFT) -#define F_BIT(b) (1 << ((b) & BANK_MASK)) - -/* Flash timeouts. These are 2x the spec sheet max. */ -#define ERASE_TIMEOUT_MS 200 -#define WRITE_TIMEOUT_US 300 - -int stuck_locked; /* Is physical flash stuck protected? */ -int all_protected; /* Has all-flash protection been requested? */ - -/** - * Protect flash banks until reboot. - * - * @param start_bank Start bank to protect - * @param bank_count Number of banks to protect - */ -static void protect_banks(int start_bank, int bank_count) -{ - int bank; - for (bank = start_bank; bank < start_bank + bank_count; bank++) - LM4_FLASH_FMPPE[F_BANK(bank)] &= ~F_BIT(bank); -} - -/** - * Perform a write-buffer operation. Buffer (FWB) and address (FMA) must be - * pre-loaded. - * - * @return EC_SUCCESS, or nonzero if error. - */ -static int write_buffer(void) -{ - int t; - - if (all_protected) - return EC_ERROR_ACCESS_DENIED; - - if (!LM4_FLASH_FWBVAL) - return EC_SUCCESS; /* Nothing to do */ - - /* Clear previous error status */ - LM4_FLASH_FCMISC = LM4_FLASH_FCRIS; - - /* Start write operation at page boundary */ - LM4_FLASH_FMC2 = 0xa4420001; - - /* - * Reload the watchdog timer, so that writing a large amount of flash - * doesn't cause a watchdog reset. - */ - watchdog_reload(); - - /* Wait for write to complete */ - for (t = 0; LM4_FLASH_FMC2 & 0x01; t += 10) { - if (t > WRITE_TIMEOUT_US) - return EC_ERROR_TIMEOUT; - udelay(10); - } - - /* Check for error conditions - program failed, erase needed, - * voltage error. */ - if (LM4_FLASH_FCRIS & 0x2e01) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -/*****************************************************************************/ -/* Physical layer APIs */ - -int crec_flash_physical_write(int offset, int size, const char *data) -{ - const uint32_t *data32 = (const uint32_t *)data; - int rv; - int i; - - if (all_protected) - return EC_ERROR_ACCESS_DENIED; - - /* Fail if offset, size, and data aren't at least word-aligned */ - if ((offset | size | (uint32_t)(uintptr_t)data) & 3) - return EC_ERROR_INVAL; - - /* Get initial write buffer index and page */ - LM4_FLASH_FMA = offset & ~(FLASH_FWB_BYTES - 1); - i = (offset >> 2) & (FLASH_FWB_WORDS - 1); - - /* Copy words into buffer */ - for (; size > 0; size -= 4) { - LM4_FLASH_FWB[i++] = *data32++; - if (i == FLASH_FWB_WORDS) { - rv = write_buffer(); - if (rv != EC_SUCCESS) - return rv; - - /* Advance to next page */ - i = 0; - LM4_FLASH_FMA += FLASH_FWB_BYTES; - } - } - - /* Handle final partial page, if any */ - if (i > 0) - return write_buffer(); - - return EC_SUCCESS; -} - -int crec_flash_physical_erase(int offset, int size) -{ - if (all_protected) - return EC_ERROR_ACCESS_DENIED; - - LM4_FLASH_FCMISC = LM4_FLASH_FCRIS; /* Clear previous error status */ - - for (; size > 0; size -= CONFIG_FLASH_ERASE_SIZE, - offset += CONFIG_FLASH_ERASE_SIZE) { - int t; - - /* Do nothing if already erased */ - if (crec_flash_is_erased(offset, CONFIG_FLASH_ERASE_SIZE)) - continue; - - LM4_FLASH_FMA = offset; - - /* - * Reload the watchdog timer, so that erasing many flash pages - * doesn't cause a watchdog reset. May not need this now that - * we're using msleep() below. - */ - watchdog_reload(); - - /* Start erase */ - LM4_FLASH_FMC = 0xa4420002; - - /* Wait for erase to complete */ - for (t = 0; LM4_FLASH_FMC & 0x02; t++) { - if (t > ERASE_TIMEOUT_MS) - return EC_ERROR_TIMEOUT; - msleep(1); - } - - /* Check for error conditions - erase failed, voltage error, - * protection error */ - if (LM4_FLASH_FCRIS & 0x0a01) - return EC_ERROR_UNKNOWN; - } - - return EC_SUCCESS; -} - -int crec_flash_physical_get_protect(int bank) -{ - return (LM4_FLASH_FMPPE[F_BANK(bank)] & F_BIT(bank)) ? 0 : 1; -} - -uint32_t crec_flash_physical_get_protect_flags(void) -{ - uint32_t flags = 0; - - /* Read all-protected state from our shadow copy */ - if (all_protected) - flags |= EC_FLASH_PROTECT_ALL_NOW; - - /* Check if blocks were stuck locked at pre-init */ - if (stuck_locked) - flags |= EC_FLASH_PROTECT_ERROR_STUCK; - - return flags; -} - -int crec_flash_physical_protect_now(int all) -{ - if (all) { - /* Protect the entire flash */ - all_protected = 1; - protect_banks(0, CONFIG_FLASH_SIZE_BYTES / - CONFIG_FLASH_BANK_SIZE); - } else - /* Protect the WP region (read-only section and pstate) */ - protect_banks(WP_BANK_OFFSET, WP_BANK_COUNT); - - return EC_SUCCESS; -} - -uint32_t crec_flash_physical_get_valid_flags(void) -{ - return EC_FLASH_PROTECT_RO_AT_BOOT | - EC_FLASH_PROTECT_RO_NOW | - EC_FLASH_PROTECT_ALL_NOW; -} - -uint32_t crec_flash_physical_get_writable_flags(uint32_t cur_flags) -{ - uint32_t ret = 0; - - /* If RO protection isn't enabled, its at-boot state can be changed. */ - if (!(cur_flags & EC_FLASH_PROTECT_RO_NOW)) - ret |= EC_FLASH_PROTECT_RO_AT_BOOT; - - /* - * If entire flash isn't protected at this boot, it can be enabled if - * the WP GPIO is asserted. - */ - if (!(cur_flags & EC_FLASH_PROTECT_ALL_NOW) && - (cur_flags & EC_FLASH_PROTECT_GPIO_ASSERTED)) - ret |= EC_FLASH_PROTECT_ALL_NOW; - - return ret; -} - - -/*****************************************************************************/ -/* High-level APIs */ - -int crec_flash_pre_init(void) -{ - uint32_t reset_flags = system_get_reset_flags(); - uint32_t prot_flags = crec_flash_get_protect(); - uint32_t unwanted_prot_flags = EC_FLASH_PROTECT_ALL_NOW | - EC_FLASH_PROTECT_ERROR_INCONSISTENT; - - /* - * If we have already jumped between images, an earlier image could - * have applied write protection. Nothing additional needs to be done. - */ - if (reset_flags & EC_RESET_FLAG_SYSJUMP) - return EC_SUCCESS; - - if (prot_flags & EC_FLASH_PROTECT_GPIO_ASSERTED) { - /* - * Write protect is asserted. If we want RO flash protected, - * protect it now. - */ - if ((prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) && - !(prot_flags & EC_FLASH_PROTECT_RO_NOW)) { - int rv = crec_flash_set_protect(EC_FLASH_PROTECT_RO_NOW, - EC_FLASH_PROTECT_RO_NOW); - if (rv) - return rv; - - /* Re-read flags */ - prot_flags = crec_flash_get_protect(); - } - - /* Update all-now flag if all flash is protected */ - if (prot_flags & EC_FLASH_PROTECT_ALL_NOW) - all_protected = 1; - - } else { - /* Don't want RO flash protected */ - unwanted_prot_flags |= EC_FLASH_PROTECT_RO_NOW; - } - - /* If there are no unwanted flags, done */ - if (!(prot_flags & unwanted_prot_flags)) - return EC_SUCCESS; - - /* - * If the last reboot was a power-on reset, it should have cleared - * write-protect. If it didn't, then the flash write protect registers - * have been permanently committed and we can't fix that. - */ - if (reset_flags & EC_RESET_FLAG_POWER_ON) { - stuck_locked = 1; - return EC_ERROR_ACCESS_DENIED; - } - - /* Otherwise, do a hard boot to clear the flash protection registers */ - system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS); - - /* That doesn't return, so if we're still here that's an error */ - return EC_ERROR_UNKNOWN; -} diff --git a/chip/lm4/gpio.c b/chip/lm4/gpio.c deleted file mode 100644 index fab3c97f59..0000000000 --- a/chip/lm4/gpio.c +++ /dev/null @@ -1,385 +0,0 @@ -/* Copyright 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. - */ - -/* GPIO module for Chrome EC */ - -#include "clock.h" -#include "common.h" -#include "gpio.h" -#include "hooks.h" -#include "registers.h" -#include "switch.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -/* 0-terminated list of GPIO base addresses */ -static const uint32_t gpio_bases[] = { - LM4_GPIO_A, LM4_GPIO_B, LM4_GPIO_C, LM4_GPIO_D, - LM4_GPIO_E, LM4_GPIO_F, LM4_GPIO_G, LM4_GPIO_H, - LM4_GPIO_J, LM4_GPIO_K, LM4_GPIO_L, LM4_GPIO_M, - LM4_GPIO_N, LM4_GPIO_P, LM4_GPIO_Q, 0 -}; - -/** - * Find the index of a GPIO port base address - * - * This is used by the clock gating registers. - * - * @param port_base Base address to find (LM4_GPIO_[A-Q]) - * - * @return The index, or -1 if no match. - */ -static int find_gpio_port_index(uint32_t port_base) -{ - int i; - for (i = 0; gpio_bases[i]; i++) { - if (gpio_bases[i] == port_base) - return i; - } - return -1; -} - -void gpio_set_alternate_function(uint32_t port, uint32_t mask, - enum gpio_alternate_func func) -{ - int port_index = find_gpio_port_index(port); - int cgmask; - - /* Ignore (do nothing for) invalid port values */ - if (port_index < 0) - return; - - /* Enable the GPIO port in run and sleep. */ - cgmask = 1 << port_index; - clock_enable_peripheral(CGC_OFFSET_GPIO, cgmask, - CGC_MODE_RUN | CGC_MODE_SLEEP); - - if (func != GPIO_ALT_FUNC_NONE) { - int pctlmask = 0; - int i; - /* Expand mask from bits to nibbles */ - for (i = 0; i < 8; i++) { - if (mask & BIT(i)) - pctlmask |= 1 << (4 * i); - } - - LM4_GPIO_PCTL(port) = - (LM4_GPIO_PCTL(port) & ~(pctlmask * 0xf)) | - (pctlmask * func); - LM4_GPIO_AFSEL(port) |= mask; - } else { - LM4_GPIO_AFSEL(port) &= ~mask; - } -} - -test_mockable int gpio_get_level(enum gpio_signal signal) -{ - return LM4_GPIO_DATA(gpio_list[signal].port, - gpio_list[signal].mask) ? 1 : 0; -} - -void gpio_set_level(enum gpio_signal signal, int value) -{ - /* - * Ok to write 0xff because LM4_GPIO_DATA bit-masks only the bit - * we care about. - */ - LM4_GPIO_DATA(gpio_list[signal].port, - gpio_list[signal].mask) = (value ? 0xff : 0); -} - -void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags) -{ - /* - * Select open drain first, so that we don't glitch the signal - * when changing the line to an output. - */ - if (flags & GPIO_OPEN_DRAIN) - LM4_GPIO_ODR(port) |= mask; - else - LM4_GPIO_ODR(port) &= ~mask; - - if (flags & GPIO_OUTPUT) - LM4_GPIO_DIR(port) |= mask; - else - LM4_GPIO_DIR(port) &= ~mask; - - /* Handle pullup / pulldown */ - if (flags & GPIO_PULL_UP) { - LM4_GPIO_PUR(port) |= mask; - } else if (flags & GPIO_PULL_DOWN) { - LM4_GPIO_PDR(port) |= mask; - } else { - /* No pull up/down */ - LM4_GPIO_PUR(port) &= ~mask; - LM4_GPIO_PDR(port) &= ~mask; - } - - /* Set up interrupt type */ - if (flags & (GPIO_INT_F_LOW | GPIO_INT_F_HIGH)) - LM4_GPIO_IS(port) |= mask; - else - LM4_GPIO_IS(port) &= ~mask; - - if (flags & (GPIO_INT_F_RISING | GPIO_INT_F_HIGH)) - LM4_GPIO_IEV(port) |= mask; - else - LM4_GPIO_IEV(port) &= ~mask; - - /* Handle interrupting on both edges */ - if ((flags & GPIO_INT_F_RISING) && - (flags & GPIO_INT_F_FALLING)) - LM4_GPIO_IBE(port) |= mask; - else - LM4_GPIO_IBE(port) &= ~mask; - - if (flags & GPIO_ANALOG) - LM4_GPIO_DEN(port) &= ~mask; - else - LM4_GPIO_DEN(port) |= mask; - - /* Set level */ - if (flags & GPIO_HIGH) - LM4_GPIO_DATA(port, mask) = 0xff; - else if (flags & GPIO_LOW) - LM4_GPIO_DATA(port, mask) = 0; -} - -int gpio_enable_interrupt(enum gpio_signal signal) -{ - const struct gpio_info *g = gpio_list + signal; - /* Fail if no interrupt handler */ - if (signal >= GPIO_IH_COUNT) - return EC_ERROR_UNKNOWN; - - LM4_GPIO_IM(g->port) |= g->mask; - return EC_SUCCESS; -} - -int gpio_disable_interrupt(enum gpio_signal signal) -{ - const struct gpio_info *g = gpio_list + signal; - - /* Fail if no interrupt handler */ - if (signal >= GPIO_IH_COUNT) - return EC_ERROR_UNKNOWN; - - LM4_GPIO_IM(g->port) &= ~g->mask; - return EC_SUCCESS; -} - -int gpio_clear_pending_interrupt(enum gpio_signal signal) -{ - const struct gpio_info *g = gpio_list + signal; - - /* Fail if no interrupt handler */ - if (signal >= GPIO_IH_COUNT) - return EC_ERROR_INVAL; - - LM4_GPIO_ICR(g->port) |= g->mask; - 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 ? BIT(index) : 0; -} -#endif - -void gpio_pre_init(void) -{ - const struct gpio_info *g = gpio_list; - int is_warm = 0; - int i; - - if (LM4_SYSTEM_RCGCGPIO == 0x7fff) { - /* This is a warm reboot */ - is_warm = 1; - } else { - /* - * Enable clocks to all the GPIO blocks since we use all of - * them as GPIOs in run and sleep modes. - */ - clock_enable_peripheral(CGC_OFFSET_GPIO, 0x7fff, - CGC_MODE_RUN | CGC_MODE_SLEEP); - } - - /* - * Disable GPIO commit control for PD7 and PF0, since we don't use the - * NMI pin function. - */ - LM4_GPIO_LOCK(LM4_GPIO_D) = LM4_GPIO_LOCK_UNLOCK; - LM4_GPIO_CR(LM4_GPIO_D) |= 0x80; - LM4_GPIO_LOCK(LM4_GPIO_D) = 0; - LM4_GPIO_LOCK(LM4_GPIO_F) = LM4_GPIO_LOCK_UNLOCK; - LM4_GPIO_CR(LM4_GPIO_F) |= 0x01; - LM4_GPIO_LOCK(LM4_GPIO_F) = 0; - - /* Clear SSI0 alternate function on PA2:5 */ - LM4_GPIO_AFSEL(LM4_GPIO_A) &= ~0x3c; - - /* Mask all GPIO interrupts */ - for (i = 0; gpio_bases[i]; i++) - LM4_GPIO_IM(gpio_bases[i]) = 0; - - /* Set all GPIOs to defaults */ - for (i = 0; i < GPIO_COUNT; i++, g++) { - int flags = g->flags; - - 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. - */ - if (is_warm) - flags &= ~(GPIO_LOW | GPIO_HIGH); - - /* Set up GPIO based on flags */ - gpio_set_flags_by_mask(g->port, g->mask, flags); - - /* Use as GPIO, not alternate function */ - gpio_set_alternate_function(g->port, g->mask, - GPIO_ALT_FUNC_NONE); - } - -#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 - * the keyboard input GPIO bank - that's handled separately. Of course the - * bank is different for different systems. */ -static const uint8_t gpio_irqs[] = { - LM4_IRQ_GPIOA, LM4_IRQ_GPIOB, LM4_IRQ_GPIOC, LM4_IRQ_GPIOD, - LM4_IRQ_GPIOE, LM4_IRQ_GPIOF, LM4_IRQ_GPIOG, LM4_IRQ_GPIOH, - LM4_IRQ_GPIOJ, -#if defined(KB_SCAN_ROW_IRQ) && (KB_SCAN_ROW_IRQ != LM4_IRQ_GPIOK) - LM4_IRQ_GPIOK, -#endif - LM4_IRQ_GPIOL, LM4_IRQ_GPIOM, -#if defined(KB_SCAN_ROW_IRQ) && (KB_SCAN_ROW_IRQ != LM4_IRQ_GPION) - LM4_IRQ_GPION, -#endif - LM4_IRQ_GPIOP, LM4_IRQ_GPIOQ -}; - -static void gpio_init(void) -{ - int i; - - /* Enable IRQs now that pins are set up */ - for (i = 0; i < ARRAY_SIZE(gpio_irqs); i++) - task_enable_irq(gpio_irqs[i]); -} -DECLARE_HOOK(HOOK_INIT, gpio_init, HOOK_PRIO_DEFAULT); - -/*****************************************************************************/ -/* Interrupt handlers */ - -/** - * Handle a GPIO interrupt. - * - * @param port GPIO port (LM4_GPIO_*) - * @param mis Masked interrupt status value for that port - */ -static void gpio_interrupt(int port, uint32_t mis) -{ - int i = 0; - const struct gpio_info *g = gpio_list; - - for (i = 0; i < GPIO_IH_COUNT && mis; i++, g++) { - if (port == g->port && (mis & g->mask)) { - gpio_irq_handlers[i](i); - mis &= ~g->mask; - } - } -} - -/** - * Handlers for each GPIO port. These read and clear the interrupt bits for - * the port, then call the main handler above. - */ -#define GPIO_IRQ_FUNC(irqfunc, gpiobase) \ - static void irqfunc(void) \ - { \ - uint32_t mis = LM4_GPIO_MIS(gpiobase); \ - LM4_GPIO_ICR(gpiobase) = mis; \ - gpio_interrupt(gpiobase, mis); \ - } - -GPIO_IRQ_FUNC(__gpio_a_interrupt, LM4_GPIO_A); -GPIO_IRQ_FUNC(__gpio_b_interrupt, LM4_GPIO_B); -GPIO_IRQ_FUNC(__gpio_c_interrupt, LM4_GPIO_C); -GPIO_IRQ_FUNC(__gpio_d_interrupt, LM4_GPIO_D); -GPIO_IRQ_FUNC(__gpio_e_interrupt, LM4_GPIO_E); -GPIO_IRQ_FUNC(__gpio_f_interrupt, LM4_GPIO_F); -GPIO_IRQ_FUNC(__gpio_g_interrupt, LM4_GPIO_G); -GPIO_IRQ_FUNC(__gpio_h_interrupt, LM4_GPIO_H); -GPIO_IRQ_FUNC(__gpio_j_interrupt, LM4_GPIO_J); -#if defined(KB_SCAN_ROW_GPIO) && (KB_SCAN_ROW_GPIO != LM4_GPIO_K) -GPIO_IRQ_FUNC(__gpio_k_interrupt, LM4_GPIO_K); -#endif -GPIO_IRQ_FUNC(__gpio_l_interrupt, LM4_GPIO_L); -GPIO_IRQ_FUNC(__gpio_m_interrupt, LM4_GPIO_M); -#if defined(KB_SCAN_ROW_GPIO) && (KB_SCAN_ROW_GPIO != LM4_GPIO_N) -GPIO_IRQ_FUNC(__gpio_n_interrupt, LM4_GPIO_N); -#endif -GPIO_IRQ_FUNC(__gpio_p_interrupt, LM4_GPIO_P); -GPIO_IRQ_FUNC(__gpio_q_interrupt, LM4_GPIO_Q); - -#undef GPIO_IRQ_FUNC - -/* - * Declare IRQs. Nesting this macro inside the GPIO_IRQ_FUNC macro works - * poorly because DECLARE_IRQ() stringizes its inputs. - */ -DECLARE_IRQ(LM4_IRQ_GPIOA, __gpio_a_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOB, __gpio_b_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOC, __gpio_c_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOD, __gpio_d_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOE, __gpio_e_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOF, __gpio_f_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOG, __gpio_g_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOH, __gpio_h_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOJ, __gpio_j_interrupt, 1); -#if defined(KB_SCAN_ROW_GPIO) && (KB_SCAN_ROW_GPIO != LM4_GPIO_K) -DECLARE_IRQ(LM4_IRQ_GPIOK, __gpio_k_interrupt, 1); -#endif -DECLARE_IRQ(LM4_IRQ_GPIOL, __gpio_l_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOM, __gpio_m_interrupt, 1); -#if defined(KB_SCAN_ROW_GPIO) && (KB_SCAN_ROW_GPIO != LM4_GPIO_N) -DECLARE_IRQ(LM4_IRQ_GPION, __gpio_n_interrupt, 1); -#endif -DECLARE_IRQ(LM4_IRQ_GPIOP, __gpio_p_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOQ, __gpio_q_interrupt, 1); diff --git a/chip/lm4/hwtimer.c b/chip/lm4/hwtimer.c deleted file mode 100644 index 5fb2366f7d..0000000000 --- a/chip/lm4/hwtimer.c +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright 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. - */ - -/* Hardware timers driver */ - -#include "clock.h" -#include "common.h" -#include "hooks.h" -#include "hwtimer.h" -#include "registers.h" -#include "task.h" -#include "timer.h" - -void __hw_clock_event_set(uint32_t deadline) -{ - /* set the match on the deadline */ - LM4_TIMER_TAMATCHR(6) = 0xffffffff - deadline; - /* Set the match interrupt */ - LM4_TIMER_IMR(6) |= 0x10; -} - -uint32_t __hw_clock_event_get(void) -{ - return 0xffffffff - LM4_TIMER_TAMATCHR(6); -} - -void __hw_clock_event_clear(void) -{ - /* Disable the match interrupt */ - LM4_TIMER_IMR(6) &= ~0x10; -} - -uint32_t __hw_clock_source_read(void) -{ - return 0xffffffff - LM4_TIMER_TAV(6); -} - -void __hw_clock_source_set(uint32_t ts) -{ - LM4_TIMER_TAV(6) = 0xffffffff - ts; -} - -static void __hw_clock_source_irq(void) -{ - uint32_t status = LM4_TIMER_RIS(6); - - /* Clear interrupt */ - LM4_TIMER_ICR(6) = status; - - /* - * Find expired timers and set the new timer deadline; check the IRQ - * status to determine if the free-running counter overflowed. - */ - process_timers(status & 0x01); -} -DECLARE_IRQ(LM4_IRQ_TIMERW0A, __hw_clock_source_irq, 1); - -static void update_prescaler(void) -{ - /* - * Set the prescaler to increment every microsecond. This takes - * effect immediately, because the TAILD bit in TAMR is clear. - */ - LM4_TIMER_TAPR(6) = clock_get_freq() / SECOND; -} -DECLARE_HOOK(HOOK_FREQ_CHANGE, update_prescaler, HOOK_PRIO_DEFAULT); - -int __hw_clock_source_init(uint32_t start_t) -{ - /* - * Use WTIMER0 (timer 6) configured as a free running counter with 1 us - * period. - */ - - /* 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; - /* Set overflow interrupt */ - LM4_TIMER_IMR(6) = 0x1; - /* 32-bit timer mode */ - LM4_TIMER_CFG(6) = 4; - - /* Set initial prescaler */ - update_prescaler(); - - /* Periodic mode, counting down */ - LM4_TIMER_TAMR(6) = 0x22; - /* Use the full 32-bits of the timer */ - LM4_TIMER_TAILR(6) = 0xffffffff; - /* Starts counting in timer A */ - LM4_TIMER_CTL(6) |= 0x1; - - /* - * Override the count with the start value now that counting has - * started. - */ - __hw_clock_source_set(start_t); - - /* Enable interrupt */ - task_enable_irq(LM4_IRQ_TIMERW0A); - - return LM4_IRQ_TIMERW0A; -} diff --git a/chip/lm4/i2c.c b/chip/lm4/i2c.c deleted file mode 100644 index 69c76b9eb7..0000000000 --- a/chip/lm4/i2c.c +++ /dev/null @@ -1,413 +0,0 @@ -/* Copyright 2013 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. - */ - -/* I2C port module for Chrome EC */ - -#include "atomic.h" -#include "clock.h" -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "hooks.h" -#include "i2c.h" -#include "registers.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -#define CPUTS(outstr) cputs(CC_I2C, outstr) -#define CPRINTS(format, args...) cprints(CC_I2C, format, ## args) - -/* Flags for writes to MCS */ -#define LM4_I2C_MCS_RUN BIT(0) -#define LM4_I2C_MCS_START BIT(1) -#define LM4_I2C_MCS_STOP BIT(2) -#define LM4_I2C_MCS_ACK BIT(3) -#define LM4_I2C_MCS_HS BIT(4) -#define LM4_I2C_MCS_QCMD BIT(5) - -/* Flags for reads from MCS */ -#define LM4_I2C_MCS_BUSY BIT(0) -#define LM4_I2C_MCS_ERROR BIT(1) -#define LM4_I2C_MCS_ADRACK BIT(2) -#define LM4_I2C_MCS_DATACK BIT(3) -#define LM4_I2C_MCS_ARBLST BIT(4) -#define LM4_I2C_MCS_IDLE BIT(5) -#define LM4_I2C_MCS_BUSBSY BIT(6) -#define LM4_I2C_MCS_CLKTO BIT(7) - -/* - * Minimum delay between resetting the port or sending a stop condition, - * and when the port can be expected to be back in an idle state (and - * the peripheral has had long enough to see the start/stop condition - * edges). - * - * 500 us = 50 clocks at 100 KHz bus speed. This has been experimentally - * determined to be enough. - */ -#define I2C_IDLE_US 500 - -/* IRQ for each port */ -static const uint32_t i2c_irqs[] = {LM4_IRQ_I2C0, LM4_IRQ_I2C1, LM4_IRQ_I2C2, - LM4_IRQ_I2C3, LM4_IRQ_I2C4, LM4_IRQ_I2C5}; -BUILD_ASSERT(ARRAY_SIZE(i2c_irqs) == I2C_PORT_COUNT); - -/* I2C port state data */ -struct i2c_port_data { - const uint8_t *out; /* Output data pointer */ - int out_size; /* Output data to transfer, in bytes */ - uint8_t *in; /* Input data pointer */ - int in_size; /* Input data to transfer, in bytes */ - int flags; /* Flags (I2C_XFER_*) */ - int idx; /* Index into input/output data */ - int err; /* Error code, if any */ - uint32_t timeout_us; /* Transaction timeout, or 0 to use default */ - - /* Task waiting on port, or TASK_ID_INVALID if none. */ - volatile int task_waiting; -}; -static struct i2c_port_data pdata[I2C_PORT_COUNT]; - -int i2c_is_busy(int port) -{ - return LM4_I2C_MCS(port) & LM4_I2C_MCS_BUSBSY; -} - -/** - * I2C transfer engine. - * - * @return Zero when done with transfer (ready to wake task). - * - * MCS sequence on multi-byte write: - * 0x3 0x1 0x1 ... 0x1 0x5 - * Single byte write: - * 0x7 - * - * MCS receive sequence on multi-byte read: - * 0xb 0x9 0x9 ... 0x9 0x5 - * Single byte read: - * 0x7 - */ -int i2c_do_work(int port) -{ - struct i2c_port_data *pd = pdata + port; - uint32_t reg_mcs = LM4_I2C_MCS_RUN; - - if (pd->flags & I2C_XFER_START) { - /* Set start bit on first byte */ - reg_mcs |= LM4_I2C_MCS_START; - pd->flags &= ~I2C_XFER_START; - } else if (LM4_I2C_MCS(port) & (LM4_I2C_MCS_CLKTO | LM4_I2C_MCS_ARBLST | - LM4_I2C_MCS_ERROR)) { - /* - * Error after starting; abort transfer. Ignore errors at - * start because arbitration and timeout errors are taken care - * of in chip_i2c_xfer(), and peripheral ack failures will - * automatically clear once we send a start condition. - */ - pd->err = EC_ERROR_UNKNOWN; - return 0; - } - - if (pd->out_size) { - /* Send next byte of output */ - LM4_I2C_MDR(port) = *(pd->out++); - pd->idx++; - - /* Handle starting to send last byte */ - if (pd->idx == pd->out_size) { - - /* Done with output after this */ - pd->out_size = 0; - pd->idx = 0; - - /* Resend start bit when changing direction */ - pd->flags |= I2C_XFER_START; - - /* - * Send stop bit after last byte if the stop flag is - * on, and caller doesn't expect to receive data. - */ - if ((pd->flags & I2C_XFER_STOP) && pd->in_size == 0) - reg_mcs |= LM4_I2C_MCS_STOP; - } - - LM4_I2C_MCS(port) = reg_mcs; - return 1; - - } else if (pd->in_size) { - if (pd->idx) { - /* Copy the byte we just read */ - *(pd->in++) = LM4_I2C_MDR(port) & 0xff; - } else { - /* Starting receive; switch to receive address */ - LM4_I2C_MSA(port) |= 0x01; - } - - if (pd->idx < pd->in_size) { - /* More data to read */ - pd->idx++; - - /* ACK all bytes except the last one */ - if ((pd->flags & I2C_XFER_STOP) && - pd->idx == pd->in_size) - reg_mcs |= LM4_I2C_MCS_STOP; - else - reg_mcs |= LM4_I2C_MCS_ACK; - - LM4_I2C_MCS(port) = reg_mcs; - return 1; - } - } - - /* If we're still here, done with transfer */ - return 0; -} - -int chip_i2c_xfer(const int port, const uint16_t addr_flags, - const uint8_t *out, int out_size, - uint8_t *in, int in_size, int flags) -{ - struct i2c_port_data *pd = pdata + port; - uint32_t reg_mcs = LM4_I2C_MCS(port); - int events = 0; - - if (out_size == 0 && in_size == 0) - return EC_SUCCESS; - - /* Copy data to port struct */ - pd->out = out; - pd->out_size = out_size; - pd->in = in; - pd->in_size = in_size; - pd->flags = flags; - pd->idx = 0; - pd->err = 0; - - /* Make sure we're in a good state to start */ - if ((flags & I2C_XFER_START) && - ((reg_mcs & (LM4_I2C_MCS_CLKTO | LM4_I2C_MCS_ARBLST)) || - (i2c_get_line_levels(port) != I2C_LINE_IDLE))) { - uint32_t tpr = LM4_I2C_MTPR(port); - - CPRINTS("I2C%d Addr:%02X bad status 0x%02x, SCL=%d, SDA=%d", - port, - I2C_STRIP_FLAGS(addr_flags), - reg_mcs, - i2c_get_line_levels(port) & I2C_LINE_SCL_HIGH, - i2c_get_line_levels(port) & I2C_LINE_SDA_HIGH); - - /* Attempt to unwedge the port. */ - i2c_unwedge(port); - - /* Clock timeout or arbitration lost. Reset port to clear. */ - atomic_or(LM4_SYSTEM_SRI2C_ADDR, BIT(port)); - clock_wait_cycles(3); - atomic_clear_bits(LM4_SYSTEM_SRI2C_ADDR, BIT(port)); - clock_wait_cycles(3); - - /* Restore settings */ - LM4_I2C_MCR(port) = 0x10; - LM4_I2C_MTPR(port) = tpr; - - /* - * We don't know what edges the peripheral saw, so sleep - * long enough that the peripheral will see the new - * start condition below. - */ - usleep(I2C_IDLE_US); - } - - /* Set peripheral address for transmit */ - LM4_I2C_MSA(port) = (I2C_STRIP_FLAGS(addr_flags) << 1) & 0xff; - - /* Enable interrupts */ - pd->task_waiting = task_get_current(); - LM4_I2C_MICR(port) = 0x03; - LM4_I2C_MIMR(port) = 0x03; - - /* Kick the port interrupt handler to start the transfer */ - task_trigger_irq(i2c_irqs[port]); - - /* Wait for transfer complete or timeout */ - events = task_wait_event_mask(TASK_EVENT_I2C_IDLE, pd->timeout_us); - - /* Disable interrupts */ - LM4_I2C_MIMR(port) = 0x00; - pd->task_waiting = TASK_ID_INVALID; - - /* Handle timeout */ - if (events & TASK_EVENT_TIMER) - pd->err = EC_ERROR_TIMEOUT; - - if (pd->err) { - /* Force port back idle */ - LM4_I2C_MCS(port) = LM4_I2C_MCS_STOP; - usleep(I2C_IDLE_US); - } - - return pd->err; -} - -int i2c_raw_get_scl(int port) -{ - enum gpio_signal g; - int ret; - - /* If no SCL pin defined for this port, then return 1 to appear idle. */ - if (get_scl_from_i2c_port(port, &g) != EC_SUCCESS) - return 1; - - /* If we are driving the pin low, it must be low. */ - if (gpio_get_level(g) == 0) - return 0; - - /* - * Otherwise, we need to toggle it to an input to read the true pin - * state. - */ - gpio_set_flags(g, GPIO_INPUT); - ret = gpio_get_level(g); - gpio_set_flags(g, GPIO_ODR_HIGH); - - return ret; -} - -int i2c_raw_get_sda(int port) -{ - enum gpio_signal g; - int ret; - - /* If no SDA pin defined for this port, then return 1 to appear idle. */ - if (get_sda_from_i2c_port(port, &g) != EC_SUCCESS) - return 1; - - /* If we are driving the pin low, it must be low. */ - if (gpio_get_level(g) == 0) - return 0; - - /* - * Otherwise, we need to toggle it to an input to read the true pin - * state. - */ - gpio_set_flags(g, GPIO_INPUT); - ret = gpio_get_level(g); - gpio_set_flags(g, GPIO_ODR_HIGH); - - return ret; -} - -int i2c_get_line_levels(int port) -{ - /* Conveniently, MBMON bit BIT(1) is SDA and BIT(0) is SCL. */ - return LM4_I2C_MBMON(port) & 0x03; -} - -void i2c_set_timeout(int port, uint32_t timeout) -{ - pdata[port].timeout_us = timeout ? timeout : I2C_TIMEOUT_DEFAULT_US; -} - -/*****************************************************************************/ -/* Hooks */ - -static void i2c_freq_changed(void) -{ - int freq = clock_get_freq(); - int i; - - for (i = 0; i < i2c_ports_used; i++) { - /* - * From datasheet: - * SCL_PRD = 2 * (1 + TPR) * (SCL_LP + SCL_HP) * CLK_PRD - * - * so: - * TPR = SCL_PRD / (2 * (SCL_LP + SCL_HP) * CLK_PRD) - 1 - * - * converting from period to frequency: - * TPR = CLK_FREQ / (SCL_FREQ * 2 * (SCL_LP + SCL_HP)) - 1 - */ - const int d = 2 * (6 + 4) * (i2c_ports[i].kbps * 1000); - - /* Round TPR up, so desired kbps is an upper bound */ - const int tpr = (freq + d - 1) / d - 1; - -#ifdef PRINT_I2C_SPEEDS - const int f = freq / (2 * (1 + tpr) * (6 + 4)); - CPRINTS("I2C%d clk=%d tpr=%d freq=%d", - i2c_ports[i].port, freq, tpr, f); -#endif - - LM4_I2C_MTPR(i2c_ports[i].port) = tpr; - } -} -DECLARE_HOOK(HOOK_FREQ_CHANGE, i2c_freq_changed, HOOK_PRIO_DEFAULT); - -void i2c_init(void) -{ - uint32_t mask = 0; - int i; - - /* Enable I2C modules in run and sleep modes. */ - for (i = 0; i < i2c_ports_used; i++) - mask |= 1 << i2c_ports[i].port; - - clock_enable_peripheral(CGC_OFFSET_I2C, mask, - CGC_MODE_RUN | CGC_MODE_SLEEP); - - /* Configure GPIOs */ - gpio_config_module(MODULE_I2C, 1); - - /* Initialize ports as controller, with interrupts enabled */ - for (i = 0; i < i2c_ports_used; i++) - LM4_I2C_MCR(i2c_ports[i].port) = 0x10; - - /* Set initial clock frequency */ - i2c_freq_changed(); - - /* Enable IRQs; no tasks are waiting on ports */ - for (i = 0; i < I2C_PORT_COUNT; i++) { - pdata[i].task_waiting = TASK_ID_INVALID; - task_enable_irq(i2c_irqs[i]); - - /* Use default timeout */ - i2c_set_timeout(i, 0); - } -} - -/** - * Handle an interrupt on the specified port. - * - * @param port I2C port generating interrupt - */ -static void handle_interrupt(int port) -{ - int id = pdata[port].task_waiting; - - /* Clear the interrupt status */ - LM4_I2C_MICR(port) = LM4_I2C_MMIS(port); - - /* If no task is waiting, just return */ - if (id == TASK_ID_INVALID) - return; - - /* If done doing work, wake up the task waiting for the transfer */ - if (!i2c_do_work(port)) - task_set_event(id, TASK_EVENT_I2C_IDLE); -} - -static void i2c0_interrupt(void) { handle_interrupt(0); } -static void i2c1_interrupt(void) { handle_interrupt(1); } -static void i2c2_interrupt(void) { handle_interrupt(2); } -static void i2c3_interrupt(void) { handle_interrupt(3); } -static void i2c4_interrupt(void) { handle_interrupt(4); } -static void i2c5_interrupt(void) { handle_interrupt(5); } - -DECLARE_IRQ(LM4_IRQ_I2C0, i2c0_interrupt, 2); -DECLARE_IRQ(LM4_IRQ_I2C1, i2c1_interrupt, 2); -DECLARE_IRQ(LM4_IRQ_I2C2, i2c2_interrupt, 2); -DECLARE_IRQ(LM4_IRQ_I2C3, i2c3_interrupt, 2); -DECLARE_IRQ(LM4_IRQ_I2C4, i2c4_interrupt, 2); -DECLARE_IRQ(LM4_IRQ_I2C5, i2c5_interrupt, 2); diff --git a/chip/lm4/keyboard_raw.c b/chip/lm4/keyboard_raw.c deleted file mode 100644 index 526a6bad20..0000000000 --- a/chip/lm4/keyboard_raw.c +++ /dev/null @@ -1,119 +0,0 @@ -/* Copyright 2013 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. - */ - -/* Functions needed by keyboard scanner module for Chrome EC */ - -#include "common.h" -#include "keyboard_raw.h" -#include "keyboard_scan.h" -#include "registers.h" -#include "task.h" - -void keyboard_raw_init(void) -{ - /* Ensure top-level interrupt is disabled */ - keyboard_raw_enable_interrupt(0); - - /* - * Set column outputs as open-drain; we either pull them low or let - * them float high. - */ - LM4_GPIO_AFSEL(LM4_GPIO_P) = 0; /* KSO[7:0] */ - LM4_GPIO_AFSEL(LM4_GPIO_Q) &= ~0x1f; /* KSO[12:8] */ - LM4_GPIO_DEN(LM4_GPIO_P) = 0xff; - LM4_GPIO_DEN(LM4_GPIO_Q) |= 0x1f; - LM4_GPIO_DIR(LM4_GPIO_P) = 0xff; - LM4_GPIO_DIR(LM4_GPIO_Q) |= 0x1f; - LM4_GPIO_ODR(LM4_GPIO_P) = 0xff; - LM4_GPIO_ODR(LM4_GPIO_Q) |= 0x1f; - -#ifdef CONFIG_KEYBOARD_COL2_INVERTED - /* - * When column 2 is inverted, the Silego has a pulldown instead of a - * pullup. So drive it push-pull instead of open-drain. - */ - LM4_GPIO_ODR(LM4_GPIO_P) &= ~BIT(2); -#endif - - /* Set row inputs with pull-up */ - LM4_GPIO_AFSEL(KB_SCAN_ROW_GPIO) &= 0xff; - LM4_GPIO_DEN(KB_SCAN_ROW_GPIO) |= 0xff; - LM4_GPIO_DIR(KB_SCAN_ROW_GPIO) = 0; - LM4_GPIO_PUR(KB_SCAN_ROW_GPIO) = 0xff; - - /* Edge-sensitive on both edges. */ - LM4_GPIO_IS(KB_SCAN_ROW_GPIO) = 0; - LM4_GPIO_IBE(KB_SCAN_ROW_GPIO) = 0xff; - - /* - * Enable interrupts for the inputs. The top-level interrupt is still - * masked off, so this won't trigger interrupts yet. - */ - LM4_GPIO_IM(KB_SCAN_ROW_GPIO) = 0xff; -} - -void keyboard_raw_task_start(void) -{ - task_enable_irq(KB_SCAN_ROW_IRQ); -} - -test_mockable void keyboard_raw_drive_column(int col) -{ - int mask; - - if (col == KEYBOARD_COLUMN_NONE) - mask = 0x1fff; /* Tri-state all outputs */ - else if (col == KEYBOARD_COLUMN_ALL) - mask = 0; /* Assert all outputs */ - else - mask = 0x1fff ^ BIT(col); /* Assert a single output */ - -#ifdef CONFIG_KEYBOARD_COL2_INVERTED - /* Invert column 2 output */ - mask ^= BIT(2); -#endif - - LM4_GPIO_DATA(LM4_GPIO_P, 0xff) = mask & 0xff; - LM4_GPIO_DATA(LM4_GPIO_Q, 0x1f) = (mask >> 8) & 0x1f; -} - -test_mockable int keyboard_raw_read_rows(void) -{ - /* Bits are active-low, so invert returned levels */ - return LM4_GPIO_DATA(KB_SCAN_ROW_GPIO, 0xff) ^ 0xff; -} - -void keyboard_raw_enable_interrupt(int enable) -{ - if (enable) { - /* - * Clear pending interrupts before enabling them, because the - * raw interrupt status may have been tripped by keyboard - * scanning or, if a key is already pressed, by driving all the - * outputs. - * - * We won't lose keyboard events because the scanning task will - * explicitly check the raw row state before waiting for an - * interrupt. If a key is pressed, the task won't wait. - */ - LM4_GPIO_ICR(KB_SCAN_ROW_GPIO) = 0xff; - LM4_GPIO_IM(KB_SCAN_ROW_GPIO) = 0xff; - } else { - LM4_GPIO_IM(KB_SCAN_ROW_GPIO) = 0; - } -} - -/** - * Interrupt handler for the entire GPIO bank of keyboard rows. - */ -static void keyboard_raw_interrupt(void) -{ - /* Clear all pending keyboard interrupts */ - LM4_GPIO_ICR(KB_SCAN_ROW_GPIO) = 0xff; - - /* Wake the scan task */ - task_wake(TASK_ID_KEYSCAN); -} -DECLARE_IRQ(KB_SCAN_ROW_IRQ, keyboard_raw_interrupt, 3); diff --git a/chip/lm4/lpc.c b/chip/lm4/lpc.c deleted file mode 100644 index 3f1b7b0b44..0000000000 --- a/chip/lm4/lpc.c +++ /dev/null @@ -1,835 +0,0 @@ -/* Copyright 2013 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. - */ - -/* LPC module for Chrome EC */ - -#include "acpi.h" -#include "clock.h" -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "hooks.h" -#include "host_command.h" -#include "keyboard_protocol.h" -#include "lpc.h" -#include "port80.h" -#include "pwm.h" -#include "registers.h" -#include "system.h" -#include "task.h" -#include "timer.h" -#include "uart.h" -#include "util.h" - -/* LPC channels */ -#define LPC_CH_ACPI 0 /* ACPI commands */ -#define LPC_CH_PORT80 1 /* Port 80 debug output */ -#define LPC_CH_CMD_DATA 2 /* Data for host commands (args/params/response) */ -#define LPC_CH_KEYBOARD 3 /* 8042 keyboard emulation */ -#define LPC_CH_CMD 4 /* Host commands */ -#define LPC_CH_MEMMAP 5 /* Memory-mapped data */ -#define LPC_CH_COMX 7 /* UART emulation */ -/* LPC pool offsets */ -#define LPC_POOL_OFFS_ACPI 0 /* ACPI commands - 0=in, 1=out */ -#define LPC_POOL_OFFS_PORT80 4 /* Port 80 - 4=in, 5=out */ -#define LPC_POOL_OFFS_COMX 8 /* UART emulation range - 8-15 */ -#define LPC_POOL_OFFS_KEYBOARD 16 /* Keyboard - 16=in, 17=out */ -#define LPC_POOL_OFFS_CMD 20 /* Host commands - 20=in, 21=out */ -#define LPC_POOL_OFFS_CMD_DATA 512 /* Data range for host commands - 512-767 */ -#define LPC_POOL_OFFS_MEMMAP 768 /* Memory-mapped data - 768-1023 */ -/* LPC pool data pointers */ -#define LPC_POOL_ACPI (LM4_LPC_LPCPOOL + LPC_POOL_OFFS_ACPI) -#define LPC_POOL_PORT80 (LM4_LPC_LPCPOOL + LPC_POOL_OFFS_PORT80) -#define LPC_POOL_COMX (LM4_LPC_LPCPOOL + LPC_POOL_OFFS_COMX) -#define LPC_POOL_KEYBOARD (LM4_LPC_LPCPOOL + LPC_POOL_OFFS_KEYBOARD) -#define LPC_POOL_CMD (LM4_LPC_LPCPOOL + LPC_POOL_OFFS_CMD) -#define LPC_POOL_CMD_DATA (LM4_LPC_LPCPOOL + LPC_POOL_OFFS_CMD_DATA) -#define LPC_POOL_MEMMAP (LM4_LPC_LPCPOOL + LPC_POOL_OFFS_MEMMAP) -/* LPC COMx I/O address (in x86 I/O address space) */ -#define LPC_COMX_ADDR 0x3f8 /* COM1 */ - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_LPC, outstr) -#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args) - -static struct host_packet lpc_packet; -static struct host_cmd_handler_args host_cmd_args; -static uint8_t host_cmd_flags; /* Flags from host command */ - -/* Params must be 32-bit aligned */ -static uint8_t params_copy[EC_LPC_HOST_PACKET_SIZE] __aligned(4); -static int init_done; - -static uint8_t * const cmd_params = (uint8_t *)LPC_POOL_CMD_DATA + - EC_LPC_ADDR_HOST_PARAM - EC_LPC_ADDR_HOST_ARGS; -static struct ec_lpc_host_args * const lpc_host_args = - (struct ec_lpc_host_args *)LPC_POOL_CMD_DATA; - -static void wait_irq_sent(void) -{ - /* - * A hard-coded delay here isn't very elegant, but it's the best we can - * manage (and it's a short delay, so it's not that horrible). We need - * this because SIRQRIS isn't cleared in continuous mode, and the EC - * has trouble sending more than 1 frame in quiet mode. Waiting 4 us = - * 2 SERIRQ frames ensures the IRQ has been sent out. - */ - udelay(4); -} - -#ifdef CONFIG_KEYBOARD_IRQ_GPIO -static void keyboard_irq_assert(void) -{ - /* - * Enforce signal-high for long enough for the signal to be pulled high - * by the external pullup resistor. This ensures the host will see the - * following falling edge, regardless of the line state before this - * function call. - */ - uint64_t tstop = get_time().val + MSEC; - gpio_set_level(CONFIG_KEYBOARD_IRQ_GPIO, 1); - udelay(4); - /* Generate a falling edge */ - gpio_set_level(CONFIG_KEYBOARD_IRQ_GPIO, 0); - /* Wait for host senses the interrupt and gets the char. */ - do { - if (get_time().val > tstop) - break; - } while (lpc_keyboard_has_char()); - /* Set signal high, now that we've generated the edge */ - gpio_set_level(CONFIG_KEYBOARD_IRQ_GPIO, 1); -} -#else -static void wait_send_serirq(uint32_t lpcirqctl) -{ - LM4_LPC_LPCIRQCTL = lpcirqctl; - wait_irq_sent(); -} - -/** - * Manually generate an IRQ to host (edge-trigger). - * - * @param irq_num IRQ number to generate. Pass 0 to set the AH - * (active high) bit. - * - * For SERIRQ quite mode, we need to set LM4_LPC_LPCIRQCTL twice. - * The first one is to assert IRQ (pull low), and then the second one is - * to de-assert it. This generates a pulse (high-low-high) for an IRQ. - */ -static void lpc_manual_irq(int irq_num) -{ - uint32_t common_bits = - 0x00000004 | /* PULSE */ - 0x00000002 | /* ONCHG - for quiet mode */ - 0x00000001; /* SND - send immediately */ - - /* Send out the IRQ first. */ - wait_send_serirq((1 << (irq_num + 16)) | common_bits); - - /* Generate a all-high frame to simulate a rising edge. */ - wait_send_serirq(common_bits); -} - -static inline void keyboard_irq_assert(void) -{ - /* Use serirq method. */ - lpc_manual_irq(1); /* IRQ#1 */ -} -#endif - -/** - * Generate SMI pulse to the host chipset via GPIO. - * - * If the x86 is in S0, SMI# is sampled at 33MHz, so minimum pulse length is - * 60ns. If the x86 is in S3, SMI# is sampled at 32.768KHz, so we need pulse - * length >61us. Both are short enough and events are infrequent, so just - * delay for 65us. - */ -static void lpc_generate_smi(void) -{ - host_event_t smi; - - /* Enforce signal-high for long enough to debounce high */ - gpio_set_level(GPIO_PCH_SMI_L, 1); - udelay(65); - /* Generate a falling edge */ - gpio_set_level(GPIO_PCH_SMI_L, 0); - udelay(65); - /* Set signal high, now that we've generated the edge */ - gpio_set_level(GPIO_PCH_SMI_L, 1); - - smi = lpc_get_host_events_by_type(LPC_HOST_EVENT_SMI); - if (smi) - HOST_EVENT_CPRINTS("smi", smi); -} - -/** - * Generate SCI pulse to the host chipset via LPC0SCI. - */ -static void lpc_generate_sci(void) -{ - host_event_t sci; - -#ifdef CONFIG_SCI_GPIO - /* Enforce signal-high for long enough to debounce high */ - gpio_set_level(CONFIG_SCI_GPIO, 1); - udelay(65); - /* Generate a falling edge */ - gpio_set_level(CONFIG_SCI_GPIO, 0); - udelay(65); - /* Set signal high, now that we've generated the edge */ - gpio_set_level(CONFIG_SCI_GPIO, 1); -#else - LM4_LPC_LPCCTL |= LM4_LPC_SCI_START; -#endif - - sci = lpc_get_host_events_by_type(LPC_HOST_EVENT_SCI); - if (sci) - HOST_EVENT_CPRINTS("sci", sci); -} - -/** - * Update the level-sensitive wake signal to the AP. - * - * @param wake_events Currently asserted wake events - */ -static void lpc_update_wake(uint64_t wake_events) -{ - /* - * Mask off power button event, since the AP gets that through a - * separate dedicated GPIO. - */ - wake_events &= ~EC_HOST_EVENT_MASK(EC_HOST_EVENT_POWER_BUTTON); - - /* Signal is asserted low when wake events is non-zero */ - gpio_set_level(GPIO_PCH_WAKE_L, !wake_events); -} - -uint8_t *lpc_get_memmap_range(void) -{ - return (uint8_t *)LPC_POOL_MEMMAP; -} - -static void lpc_send_response(struct host_cmd_handler_args *args) -{ - uint8_t *out; - int size = args->response_size; - int csum; - int i; - - /* Ignore in-progress on LPC since interface is synchronous anyway */ - if (args->result == EC_RES_IN_PROGRESS) - return; - - /* Handle negative size */ - if (size < 0) { - args->result = EC_RES_INVALID_RESPONSE; - size = 0; - } - - /* New-style response */ - lpc_host_args->flags = - (host_cmd_flags & ~EC_HOST_ARGS_FLAG_FROM_HOST) | - EC_HOST_ARGS_FLAG_TO_HOST; - - lpc_host_args->data_size = size; - - csum = args->command + lpc_host_args->flags + - lpc_host_args->command_version + - lpc_host_args->data_size; - - for (i = 0, out = (uint8_t *)args->response; i < size; i++, out++) - csum += *out; - - lpc_host_args->checksum = (uint8_t)csum; - - /* Fail if response doesn't fit in the param buffer */ - if (size > EC_PROTO2_MAX_PARAM_SIZE) - args->result = EC_RES_INVALID_RESPONSE; - - /* Write result to the data byte. This sets the TOH status bit. */ - LPC_POOL_CMD[1] = args->result; - - /* Clear the busy bit, so the host knows the EC is done. */ - task_disable_irq(LM4_IRQ_LPC); - LM4_LPC_ST(LPC_CH_CMD) &= ~LM4_LPC_ST_BUSY; - task_enable_irq(LM4_IRQ_LPC); -} - -static void lpc_send_response_packet(struct host_packet *pkt) -{ - /* Ignore in-progress on LPC since interface is synchronous anyway */ - if (pkt->driver_result == EC_RES_IN_PROGRESS) - return; - - /* Write result to the data byte. This sets the TOH status bit. */ - LPC_POOL_CMD[1] = pkt->driver_result; - - /* Clear the busy bit, so the host knows the EC is done. */ - task_disable_irq(LM4_IRQ_LPC); - LM4_LPC_ST(LPC_CH_CMD) &= ~LM4_LPC_ST_BUSY; - task_enable_irq(LM4_IRQ_LPC); -} - -int lpc_keyboard_has_char(void) -{ - return (LM4_LPC_ST(LPC_CH_KEYBOARD) & LM4_LPC_ST_TOH) ? 1 : 0; -} - -/* Return true if the FRMH is set */ -int lpc_keyboard_input_pending(void) -{ - return (LM4_LPC_ST(LPC_CH_KEYBOARD) & LM4_LPC_ST_FRMH) ? 1 : 0; -} - -/* Put a char to host buffer and send IRQ if specified. */ -void lpc_keyboard_put_char(uint8_t chr, int send_irq) -{ - LPC_POOL_KEYBOARD[1] = chr; - if (send_irq) - keyboard_irq_assert(); -} - -void lpc_keyboard_clear_buffer(void) -{ - /* Make sure the previous TOH and IRQ has been sent out. */ - wait_irq_sent(); - - LM4_LPC_ST(LPC_CH_KEYBOARD) &= ~LM4_LPC_ST_TOH; - - /* Ensure there is no TOH set in this period. */ - wait_irq_sent(); -} - -void lpc_keyboard_resume_irq(void) -{ - if (lpc_keyboard_has_char()) - keyboard_irq_assert(); -} - -#ifdef CONFIG_UART_HOST - -int lpc_comx_has_char(void) -{ - return LM4_LPC_ST(LPC_CH_COMX) & LM4_LPC_ST_FRMH; -} - -int lpc_comx_get_char(void) -{ - return LPC_POOL_COMX[0]; -} - -void lpc_comx_put_char(int c) -{ - LPC_POOL_COMX[1] = c; - - /* - * We could in theory manually trigger an IRQ, like we do for the 8042 - * keyboard interface, but neither the kernel nor BIOS seems to require - * this. - */ -} - -#endif /* CONFIG_UART_HOST */ - -/** - * Update the host event status. - * - * Sends a pulse if masked event status becomes non-zero: - * - SMI pulse via EC_SMI_L GPIO - * - SCI pulse via LPC0SCI - */ -void lpc_update_host_event_status(void) -{ - int need_sci = 0; - int need_smi = 0; - - if (!init_done) - return; - - /* Disable LPC interrupt while updating status register */ - task_disable_irq(LM4_IRQ_LPC); - - if (lpc_get_host_events_by_type(LPC_HOST_EVENT_SMI)) { - /* Only generate SMI for first event */ - if (!(LM4_LPC_ST(LPC_CH_ACPI) & LM4_LPC_ST_SMI)) - need_smi = 1; - LM4_LPC_ST(LPC_CH_ACPI) |= LM4_LPC_ST_SMI; - } else - LM4_LPC_ST(LPC_CH_ACPI) &= ~LM4_LPC_ST_SMI; - - if (lpc_get_host_events_by_type(LPC_HOST_EVENT_SCI)) { - /* Generate SCI for every event */ - need_sci = 1; - LM4_LPC_ST(LPC_CH_ACPI) |= LM4_LPC_ST_SCI; - } else - LM4_LPC_ST(LPC_CH_ACPI) &= ~LM4_LPC_ST_SCI; - - /* Copy host events to mapped memory */ - *(host_event_t *)host_get_memmap(EC_MEMMAP_HOST_EVENTS) = - lpc_get_host_events(); - - task_enable_irq(LM4_IRQ_LPC); - - /* Process the wake events. */ - lpc_update_wake(lpc_get_host_events_by_type(LPC_HOST_EVENT_WAKE)); - - /* Send pulse on SMI signal if needed */ - if (need_smi) - lpc_generate_smi(); - - /* ACPI 5.0-12.6.1: Generate SCI for SCI_EVT=1. */ - if (need_sci) - lpc_generate_sci(); -} - -void lpc_set_acpi_status_mask(uint8_t mask) -{ - uint32_t set_mask = 0; - if (mask & EC_LPC_STATUS_BURST_MODE) - set_mask |= LM4_LPC_ST_BURST; - - LM4_LPC_ST(LPC_CH_ACPI) |= set_mask; -} - -void lpc_clear_acpi_status_mask(uint8_t mask) -{ - uint32_t clear_mask = 0; - if (mask & EC_LPC_STATUS_BURST_MODE) - clear_mask |= LM4_LPC_ST_BURST; - - LM4_LPC_ST(LPC_CH_ACPI) &= ~clear_mask; -} - -int lpc_get_pltrst_asserted(void) -{ - return (LM4_LPC_LPCSTS & BIT(10)) ? 1 : 0; -} - -/** - * Handle write to ACPI I/O port - * - * @param is_cmd Is write command (is_cmd=1) or data (is_cmd=0) - */ -static void handle_acpi_write(int is_cmd) -{ - uint8_t value, result; - - /* Set the busy bit */ - LM4_LPC_ST(LPC_CH_ACPI) |= LM4_LPC_ST_BUSY; - - /* Read command/data; this clears the FRMH status bit. */ - value = LPC_POOL_ACPI[0]; - - /* Handle whatever this was. */ - if (acpi_ap_to_ec(is_cmd, value, &result)) - LPC_POOL_ACPI[1] = result; - - /* Clear the busy bit */ - LM4_LPC_ST(LPC_CH_ACPI) &= ~LM4_LPC_ST_BUSY; - - /* - * ACPI 5.0-12.6.1: Generate SCI for Input Buffer Empty / Output Buffer - * Full condition on the kernel channel. - */ - lpc_generate_sci(); -} - -/** - * Handle write to host command I/O ports. - * - * @param is_cmd Is write command (1) or data (0)? - */ -static void handle_host_write(int is_cmd) -{ - /* Ignore data writes or overlapping commands from host */ - uint32_t is_overlapping = LM4_LPC_ST(LPC_CH_CMD) & LM4_LPC_ST_BUSY; - if (!is_cmd || is_overlapping) { - if (is_overlapping) - CPRINTS("LPC Ignoring overlapping HC"); - LM4_LPC_ST(LPC_CH_CMD) &= ~LM4_LPC_ST_FRMH; - return; - } - - /* Set the busy bit */ - LM4_LPC_ST(LPC_CH_CMD) |= LM4_LPC_ST_BUSY; - - /* - * Read the command byte. This clears the FRMH bit in - * the status byte. - */ - host_cmd_args.command = LPC_POOL_CMD[0]; - - host_cmd_args.result = EC_RES_SUCCESS; - host_cmd_args.send_response = lpc_send_response; - host_cmd_flags = lpc_host_args->flags; - - /* See if we have an old or new style command */ - if (host_cmd_args.command == EC_COMMAND_PROTOCOL_3) { - lpc_packet.send_response = lpc_send_response_packet; - - lpc_packet.request = (const void *)LPC_POOL_CMD_DATA; - lpc_packet.request_temp = params_copy; - lpc_packet.request_max = sizeof(params_copy); - /* Don't know the request size so pass in the entire buffer */ - lpc_packet.request_size = EC_LPC_HOST_PACKET_SIZE; - - lpc_packet.response = (void *)LPC_POOL_CMD_DATA; - lpc_packet.response_max = EC_LPC_HOST_PACKET_SIZE; - lpc_packet.response_size = 0; - - lpc_packet.driver_result = EC_RES_SUCCESS; - host_packet_receive(&lpc_packet); - return; - - } else if (host_cmd_flags & EC_HOST_ARGS_FLAG_FROM_HOST) { - /* Version 2 (link) style command */ - int size = lpc_host_args->data_size; - int csum, i; - - host_cmd_args.version = lpc_host_args->command_version; - host_cmd_args.params = params_copy; - host_cmd_args.params_size = size; - host_cmd_args.response = cmd_params; - host_cmd_args.response_max = EC_PROTO2_MAX_PARAM_SIZE; - host_cmd_args.response_size = 0; - - /* Verify params size */ - if (size > EC_PROTO2_MAX_PARAM_SIZE) { - host_cmd_args.result = EC_RES_INVALID_PARAM; - } else { - const uint8_t *src = cmd_params; - uint8_t *copy = params_copy; - - /* - * Verify checksum and copy params out of LPC space. - * This ensures the data acted on by the host command - * handler can't be changed by host writes after the - * checksum is verified. - */ - csum = host_cmd_args.command + - host_cmd_flags + - host_cmd_args.version + - host_cmd_args.params_size; - - for (i = 0; i < size; i++) { - csum += *src; - *(copy++) = *(src++); - } - - if ((uint8_t)csum != lpc_host_args->checksum) - host_cmd_args.result = EC_RES_INVALID_CHECKSUM; - } - } else { - /* Old style command, now unsupported */ - host_cmd_args.result = EC_RES_INVALID_COMMAND; - } - - /* Hand off to host command handler */ - host_command_received(&host_cmd_args); -} - -#ifdef CONFIG_CHIPSET_RESET_HOOK -static void lpc_chipset_reset(void) -{ - hook_notify(HOOK_CHIPSET_RESET); -} -DECLARE_DEFERRED(lpc_chipset_reset); -#endif - -/** - * LPC interrupt handler - */ -static void lpc_interrupt(void) -{ - uint32_t mis = LM4_LPC_LPCMIS; - uint32_t st; - - /* Clear the interrupt bits we're handling */ - LM4_LPC_LPCIC = mis; - -#ifdef HAS_TASK_HOSTCMD - /* Handle ACPI command and data writes */ - st = LM4_LPC_ST(LPC_CH_ACPI); - if (st & LM4_LPC_ST_FRMH) - handle_acpi_write(st & LM4_LPC_ST_CMD); - - /* Handle user command writes */ - st = LM4_LPC_ST(LPC_CH_CMD); - if (st & LM4_LPC_ST_FRMH) - handle_host_write(st & LM4_LPC_ST_CMD); -#endif - - /* - * Handle port 80 writes (CH0MIS1). Due to crosbug.com/p/12349 the - * interrupt status (mis & LM4_LPC_INT_MASK(LPC_CH_PORT80, 2)) - * apparently gets lost on back-to-back writes to port 80, so check the - * FRMH bit in the channel status register to see if a write is - * pending. Loop to handle bursts of back-to-back writes. - */ - while (LM4_LPC_ST(LPC_CH_PORT80) & LM4_LPC_ST_FRMH) - port_80_write(LPC_POOL_PORT80[0]); - -#ifdef HAS_TASK_KEYPROTO - /* Handle keyboard interface writes */ - st = LM4_LPC_ST(LPC_CH_KEYBOARD); - if (st & LM4_LPC_ST_FRMH) - keyboard_host_write(LPC_POOL_KEYBOARD[0], st & LM4_LPC_ST_CMD); - - if (mis & LM4_LPC_INT_MASK(LPC_CH_KEYBOARD, 1)) { - /* Host read data; wake up task to send remaining bytes */ - task_wake(TASK_ID_KEYPROTO); - } -#endif - -#ifdef CONFIG_UART_HOST - /* Handle COMx */ - if (lpc_comx_has_char()) { - /* Copy a character to the UART if there's space */ - if (uart_comx_putc_ok()) - uart_comx_putc(lpc_comx_get_char()); - } -#endif - - /* Debugging: print changes to LPC0RESET */ - if (mis & BIT(31)) { - if (LM4_LPC_LPCSTS & BIT(10)) { - int i; - - /* Store port 80 reset event */ - port_80_write(PORT_80_EVENT_RESET); - - /* - * Workaround for crosbug.com/p/12349; clear all FRMH - * bits so host writes will trigger interrupts. - */ - for (i = 0; i < 8; i++) - LM4_LPC_ST(i) &= ~LM4_LPC_ST_FRMH; - -#ifdef CONFIG_CHIPSET_RESET_HOOK - /* Notify HOOK_CHIPSET_RESET */ - hook_call_deferred(&lpc_chipset_reset_data, MSEC); -#endif - } - - CPRINTS("LPC RESET# %sasserted", - lpc_get_pltrst_asserted() ? "" : "de"); - } -} -DECLARE_IRQ(LM4_IRQ_LPC, lpc_interrupt, 2); - -/* Enable LPC ACPI-EC interrupts */ -void lpc_enable_acpi_interrupts(void) -{ - LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_ACPI, 6); -} - -/* Disable LPC ACPI-EC interrupts */ -void lpc_disable_acpi_interrupts(void) -{ - LM4_LPC_LPCIM &= ~(LM4_LPC_INT_MASK(LPC_CH_ACPI, 6)); -} - -static void lpc_init(void) -{ - /* 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; - LM4_LPC_LPCIRQCTL = 0; - - /* Configure GPIOs */ - gpio_config_module(MODULE_LPC, 1); - - /* - * Set LPC channel 0 to I/O address 0x62 (data) / 0x66 (command), - * single endpoint, offset 0 for host command/writes and 1 for EC - * data writes, pool bytes 0(data)/1(cmd) - */ - LM4_LPC_ADR(LPC_CH_ACPI) = EC_LPC_ADDR_ACPI_DATA; - LM4_LPC_CTL(LPC_CH_ACPI) = (LPC_POOL_OFFS_ACPI << (5 - 1)); - LM4_LPC_ST(LPC_CH_ACPI) = 0; - /* Unmask interrupt for host command and data writes */ - LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_ACPI, 6); - - /* - * Set LPC channel 1 to I/O address 0x80 (data), single endpoint, - * pool bytes 4(data)/5(cmd). - */ - LM4_LPC_ADR(LPC_CH_PORT80) = 0x80; - LM4_LPC_CTL(LPC_CH_PORT80) = (LPC_POOL_OFFS_PORT80 << (5 - 1)); - /* Unmask interrupt for host data writes */ - LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_PORT80, 2); - - /* - * Set LPC channel 2 to I/O address 0x880, range endpoint, - * arbitration disabled, pool bytes 512-639. To access this from - * x86, use the following command to set GEN_LPC2: - * - * pci_write32 0 0x1f 0 0x88 0x007c0801 - */ - LM4_LPC_ADR(LPC_CH_CMD_DATA) = EC_LPC_ADDR_HOST_ARGS; - LM4_LPC_CTL(LPC_CH_CMD_DATA) = 0x8019 | - (LPC_POOL_OFFS_CMD_DATA << (5 - 1)); - - /* - * Set LPC channel 3 to I/O address 0x60 (data) / 0x64 (command), - * single endpoint, offset 0 for host command/writes and 1 for EC - * data writes, pool bytes 0(data)/1(cmd) - */ - LM4_LPC_ADR(LPC_CH_KEYBOARD) = 0x60; - LM4_LPC_CTL(LPC_CH_KEYBOARD) = (BIT(24)/* IRQSEL1 */) | - (0 << 18/* IRQEN1 */) | (LPC_POOL_OFFS_KEYBOARD << (5 - 1)); - LM4_LPC_ST(LPC_CH_KEYBOARD) = 0; - /* Unmask interrupt for host command/data writes and data reads */ - LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_KEYBOARD, 7); - - /* - * Set LPC channel 4 to I/O address 0x200 (data) / 0x204 (command), - * single endpoint, offset 0 for host command/writes and 1 for EC - * data writes, pool bytes 0(data)/1(cmd) - */ - LM4_LPC_ADR(LPC_CH_CMD) = EC_LPC_ADDR_HOST_DATA; - LM4_LPC_CTL(LPC_CH_CMD) = (LPC_POOL_OFFS_CMD << (5 - 1)); - /* - * Initialize status bits to 0. We never set the ACPI burst status bit, - * so this guarantees that at least one status bit will always be 0. - * This is used by comm_lpc.c to detect that the EC is present on the - * LPC bus. See crosbug.com/p/10963. - */ - LM4_LPC_ST(LPC_CH_CMD) = 0; - /* Unmask interrupt for host command writes */ - LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_CMD, 4); - - /* - * Set LPC channel 5 to I/O address 0x900, range endpoint, - * arbitration enabled, pool bytes 768-1023. To access this from - * x86, use the following command to set GEN_LPC3: - * - * pci_write32 0 0x1f 0 0x8c 0x007c0901 - */ - LM4_LPC_ADR(LPC_CH_MEMMAP) = EC_LPC_ADDR_MEMMAP; - LM4_LPC_CTL(LPC_CH_MEMMAP) = 0x0019 | (LPC_POOL_OFFS_MEMMAP << (5 - 1)); - -#ifdef CONFIG_UART_HOST - /* - * Set LPC channel 7 to COM port I/O address. Note that channel 7 - * ignores the TYPE bit and is always an 8-byte range. - */ - LM4_LPC_ADR(LPC_CH_COMX) = LPC_COMX_ADDR; - /* - * In theory we could configure IRQSELs and set IRQEN2/CX, and then the - * host could enable IRQs on its own. So far that hasn't been - * necessary, and due to the issues with IRQs (see wait_irq_sent() - * above) it might not work anyway. - */ - LM4_LPC_CTL(LPC_CH_COMX) = 0x0004 | (LPC_POOL_OFFS_COMX << (5 - 1)); - /* Enable COMx emulation for reads and writes. */ - LM4_LPC_LPCDMACX = 0x00310000; - /* - * Unmask interrupt for host data writes. We don't need interrupts for - * reads, because there's no flow control in that direction; LPC is - * much faster than the UART, and the UART doesn't have anywhere - * sensible to buffer input anyway. - */ - LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_COMX, 2); -#endif /* CONFIG_UART_HOST */ - - /* - * Unmask LPC bus reset interrupt. This lets us monitor the PCH - * PLTRST# signal for debugging. - */ - LM4_LPC_LPCIM |= BIT(31); - - /* Enable LPC channels */ - LM4_LPC_LPCCTL = LM4_LPC_SCI_CLK_1 | - BIT(LPC_CH_ACPI) | - BIT(LPC_CH_PORT80) | - BIT(LPC_CH_CMD_DATA) | - BIT(LPC_CH_KEYBOARD) | - BIT(LPC_CH_CMD) | - BIT(LPC_CH_MEMMAP); - -#ifdef CONFIG_UART_HOST - LM4_LPC_LPCCTL |= 1 << LPC_CH_COMX; -#endif - - /* - * Ensure the EC (peripheral) has control of the memory-mapped - * I/O space. Once the EC has won arbitration for the - * memory-mapped space, it will keep control of it until it - * writes the last byte in the space. (That never happens; we - * can't use the last byte in the space because ACPI can't see - * it anyway.) - */ - while (!(LM4_LPC_ST(LPC_CH_MEMMAP) & 0x10)) { - /* Clear HW1ST */ - LM4_LPC_ST(LPC_CH_MEMMAP) &= ~0x40; - /* Do a peripheral write; this should cause SW1ST to be set */ - *LPC_POOL_MEMMAP = *LPC_POOL_MEMMAP; - } - - /* Initialize host args and memory map to all zero */ - memset(lpc_host_args, 0, sizeof(*lpc_host_args)); - memset(lpc_get_memmap_range(), 0, EC_MEMMAP_SIZE); - - /* We support LPC args and version 3 protocol */ - *(lpc_get_memmap_range() + EC_MEMMAP_HOST_CMD_FLAGS) = - EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED | - EC_HOST_CMD_FLAG_VERSION_3; - - /* Enable LPC interrupt */ - task_enable_irq(LM4_IRQ_LPC); - -#ifdef CONFIG_UART_HOST - /* Enable COMx UART */ - uart_comx_enable(); -#endif - - /* Sufficiently initialized */ - init_done = 1; - - /* Update host events now that we can copy them to memmap */ - lpc_update_host_event_status(); -} -/* - * Set prio to higher than default; this way LPC memory mapped data is ready - * before other inits try to initialize their memmap data. - */ -DECLARE_HOOK(HOOK_INIT, lpc_init, HOOK_PRIO_INIT_LPC); - -static void lpc_tick(void) -{ - /* - * Make sure pending LPC interrupts have been processed. - * This works around a LM4 bug where host writes sometimes - * don't trigger interrupts. See crosbug.com/p/13965. - */ - task_trigger_irq(LM4_IRQ_LPC); -} -DECLARE_HOOK(HOOK_TICK, lpc_tick, HOOK_PRIO_DEFAULT); - -/** - * Get protocol information - */ -static enum ec_status lpc_get_protocol_info(struct host_cmd_handler_args *args) -{ - struct ec_response_get_protocol_info *r = args->response; - - memset(r, 0, sizeof(*r)); - r->protocol_versions = BIT(2) | BIT(3); - r->max_request_packet_size = EC_LPC_HOST_PACKET_SIZE; - r->max_response_packet_size = EC_LPC_HOST_PACKET_SIZE; - r->flags = 0; - - args->response_size = sizeof(*r); - - return EC_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_GET_PROTOCOL_INFO, - lpc_get_protocol_info, - EC_VER_MASK(0)); diff --git a/chip/lm4/peci.c b/chip/lm4/peci.c deleted file mode 100644 index b3b54a64bc..0000000000 --- a/chip/lm4/peci.c +++ /dev/null @@ -1,152 +0,0 @@ -/* Copyright 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. - */ - -/* PECI interface for Chrome EC */ - -#include "chipset.h" -#include "clock.h" -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "hooks.h" -#include "peci.h" -#include "registers.h" -#include "temp_sensor.h" -#include "util.h" - -/* Initial PECI baud rate */ -#define PECI_BAUD_RATE 100000 - -/* Polling interval for PECI, in ms */ -#define PECI_POLL_INTERVAL_MS 250 - -/* - * Internal and external path delays, in ns. The external delay is a - * best-guess measurement, but we're fairly tolerant of a bad guess because - * PECI_BAUD_RATE is slow compared to PECI's actual maximum baud rate. - */ -#define PECI_TD_FET_NS 60 -#define PECI_TD_INT_NS 80 - -/* Number of controller retries. Should be between 0 and 7. */ -#define PECI_RETRY_COUNT 4 - -/* Timing negotiation error bypass. 1 = on. 0 = off. */ -#define PECI_ERROR_BYPASS 1 - -#define TEMP_AVG_LENGTH 4 /* Should be power of 2 */ -static int temp_vals[TEMP_AVG_LENGTH]; -static int temp_idx; - -int peci_get_cpu_temp(void) -{ - int v = LM4_PECI_M0D0 & 0xffff; - - if (v >= 0x8000 && v <= 0x8fff) - return -1; - - return v >> 6; -} - -int peci_temp_sensor_get_val(int idx, int *temp_ptr) -{ - int sum = 0; - int success_cnt = 0; - int i; - - if (!chipset_in_state(CHIPSET_STATE_ON)) - return EC_ERROR_NOT_POWERED; - - for (i = 0; i < TEMP_AVG_LENGTH; ++i) { - if (temp_vals[i] >= 0) { - success_cnt++; - sum += temp_vals[i]; - } - } - - /* - * Require at least two valid samples. When the AP transitions into S0, - * it is possible, depending on the timing of the PECI sample, to read - * an invalid temperature. This is very rare, but when it does happen - * the temperature returned is CONFIG_PECI_TJMAX. Requiring two valid - * samples here assures us that one bad maximum temperature reading - * when entering S0 won't cause us to trigger an over temperature. - */ - if (success_cnt < 2) - return EC_ERROR_UNKNOWN; - - *temp_ptr = sum / success_cnt; - return EC_SUCCESS; -} - -static void peci_temp_sensor_poll(void) -{ - temp_vals[temp_idx] = peci_get_cpu_temp(); - temp_idx = (temp_idx + 1) & (TEMP_AVG_LENGTH - 1); -} -DECLARE_HOOK(HOOK_TICK, peci_temp_sensor_poll, HOOK_PRIO_TEMP_SENSOR); - -static void peci_freq_changed(void) -{ - int freq = clock_get_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 = ((CONFIG_PECI_TJMAX + 273) << 22) | 0x0001 | - (PECI_RETRY_COUNT << 12) | - (PECI_ERROR_BYPASS << 11); -} -DECLARE_HOOK(HOOK_FREQ_CHANGE, peci_freq_changed, HOOK_PRIO_DEFAULT); - -static void peci_init(void) -{ - int i; - - /* 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); - - /* Set initial clock frequency */ - peci_freq_changed(); - - /* Initialize temperature reading buffer to a valid value. */ - for (i = 0; i < TEMP_AVG_LENGTH; ++i) - temp_vals[i] = 300; /* 27 C */ -} -DECLARE_HOOK(HOOK_INIT, peci_init, HOOK_PRIO_DEFAULT); - -/*****************************************************************************/ -/* Console commands */ - -static int command_peci_temp(int argc, char **argv) -{ - int t = peci_get_cpu_temp(); - if (t == -1) { - ccprintf("PECI error 0x%04x\n", LM4_PECI_M0D0 & 0xffff); - return EC_ERROR_UNKNOWN; - } - ccprintf("CPU temp = %d K = %d C\n", t, K_TO_C(t)); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(pecitemp, command_peci_temp, - NULL, - "Print CPU temperature"); diff --git a/chip/lm4/pwm.c b/chip/lm4/pwm.c deleted file mode 100644 index 38ce61714d..0000000000 --- a/chip/lm4/pwm.c +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright 2013 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. - */ - -/* PWM control module for LM4. - * - * On this chip, the PWM logic is implemented by the hardware FAN modules. - */ - -#include "clock.h" -#include "fan.h" -#include "gpio.h" -#include "hooks.h" -#include "pwm.h" -#include "pwm_chip.h" -#include "registers.h" -#include "util.h" - -void pwm_enable(enum pwm_channel ch, int enabled) -{ - fan_set_enabled(pwm_channels[ch].channel, enabled); -} - -int pwm_get_enabled(enum pwm_channel ch) -{ - return fan_get_enabled(pwm_channels[ch].channel); -} - -void pwm_set_duty(enum pwm_channel ch, int percent) -{ - if (percent < 0) - percent = 0; - else if (percent > 100) - percent = 100; - - /* Assume the fan control is active high and invert it ourselves */ - if (pwm_channels[ch].flags & PWM_CONFIG_ACTIVE_LOW) - percent = 100 - percent; - - /* Always enable the channel */ - pwm_enable(ch, 1); - - /* Set the duty cycle */ - fan_set_duty(pwm_channels[ch].channel, percent); -} - -int pwm_get_duty(enum pwm_channel ch) -{ - int percent = fan_get_duty(pwm_channels[ch].channel); - - if (pwm_channels[ch].flags & PWM_CONFIG_ACTIVE_LOW) - percent = 100 - percent; - - return percent; -} - -static void pwm_init(void) -{ - int i; - - for (i = 0; i < PWM_CH_COUNT; ++i) - fan_channel_setup(pwm_channels[i].channel, - (pwm_channels[i].flags & - PWM_CONFIG_HAS_RPM_MODE) - ? FAN_USE_RPM_MODE : 0); -} - -/* The chip-specific fan module initializes before this. */ -DECLARE_HOOK(HOOK_INIT, pwm_init, HOOK_PRIO_INIT_PWM); diff --git a/chip/lm4/pwm_chip.h b/chip/lm4/pwm_chip.h deleted file mode 100644 index ada5785495..0000000000 --- a/chip/lm4/pwm_chip.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Copyright 2013 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. - */ - -/* LM4-specific PWM module for Chrome EC */ - -#ifndef __CROS_EC_PWM_CHIP_H -#define __CROS_EC_PWM_CHIP_H - -/* Data structure to define PWM channels. */ -struct pwm_t { - /* PWM channel ID */ - int channel; - /* PWM channel flags. See include/pwm.h */ - uint32_t flags; -}; - -extern const struct pwm_t pwm_channels[]; - -#endif /* __CROS_EC_PWM_CHIP_H */ diff --git a/chip/lm4/registers.h b/chip/lm4/registers.h deleted file mode 100644 index 1065cd7f5e..0000000000 --- a/chip/lm4/registers.h +++ /dev/null @@ -1,601 +0,0 @@ -/* Copyright 2013 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. - * - * Register map for LM4x processor - */ - -#ifndef __CROS_EC_REGISTERS_H -#define __CROS_EC_REGISTERS_H - -#include "atomic.h" -#include "common.h" - -#define LM4_UART_CH0_BASE 0x4000c000 -#define LM4_UART_CH1_BASE 0x4000d000 -#define LM4_UART_CH_SEP 0x00001000 -static inline int lm4_uart_addr(int ch, int offset) -{ - return offset + LM4_UART_CH0_BASE + LM4_UART_CH_SEP * ch; -} -#define LM4UARTREG(ch, offset) REG32(lm4_uart_addr(ch, offset)) -#define LM4_UART_DR(ch) LM4UARTREG(ch, 0x000) -#define LM4_UART_FR(ch) LM4UARTREG(ch, 0x018) -#define LM4_UART_IBRD(ch) LM4UARTREG(ch, 0x024) -#define LM4_UART_FBRD(ch) LM4UARTREG(ch, 0x028) -#define LM4_UART_LCRH(ch) LM4UARTREG(ch, 0x02c) -#define LM4_UART_CTL(ch) LM4UARTREG(ch, 0x030) -#define LM4_UART_IFLS(ch) LM4UARTREG(ch, 0x034) -#define LM4_UART_IM(ch) LM4UARTREG(ch, 0x038) -#define LM4_UART_ICR(ch) LM4UARTREG(ch, 0x044) -#define LM4_UART_DMACTL(ch) LM4UARTREG(ch, 0x048) -#define LM4_UART_CC(ch) LM4UARTREG(ch, 0xfc8) - -#define LM4_SSI_BASE 0x40008000 -#define LM4_SSI_CH_SEP 0x40001000 -static inline int lm4_spi_addr(int ch, int offset) -{ - return offset + LM4_SSI_BASE + LM4_SSI_CH_SEP * ch; -} -#define LM4SSIREG(ch, offset) REG32(lm4_spi_addr(ch, offset)) -#define LM4_SSI_CR0(ch) LM4SSIREG(ch, 0x000) -#define LM4_SSI_CR1(ch) LM4SSIREG(ch, 0x004) -#define LM4_SSI_DR(ch) LM4SSIREG(ch, 0x008) -#define LM4_SSI_SR(ch) LM4SSIREG(ch, 0x00c) -#define LM4_SSI_SR_TFE BIT(0) /* Transmit FIFO empty */ -#define LM4_SSI_SR_TNF BIT(1) /* Transmit FIFO not full */ -#define LM4_SSI_SR_RNE BIT(2) /* Receive FIFO not empty */ -#define LM4_SSI_SR_RFF BIT(3) /* Receive FIFO full */ -#define LM4_SSI_SR_BSY BIT(4) /* Busy */ -#define LM4_SSI_CPSR(ch) LM4SSIREG(ch, 0x010) -#define LM4_SSI_IM(ch) LM4SSIREG(ch, 0x014) -#define LM4_SSI_RIS(ch) LM4SSIREG(ch, 0x018) -#define LM4_SSI_MIS(ch) LM4SSIREG(ch, 0x01c) -#define LM4_SSI_ICR(ch) LM4SSIREG(ch, 0x020) -#define LM4_SSI_DMACTL(ch) LM4SSIREG(ch, 0x024) -#define LM4_SSI_CC(ch) LM4SSIREG(ch, 0xfc8) - -#define LM4_ADC_ADCACTSS REG32(0x40038000) -#define LM4_ADC_ADCRIS REG32(0x40038004) -#define LM4_ADC_ADCIM REG32(0x40038008) -#define LM4_ADC_ADCISC REG32(0x4003800c) -#define LM4_ADC_ADCOSTAT REG32(0x40038010) -#define LM4_ADC_ADCEMUX REG32(0x40038014) -#define LM4_ADC_ADCUSTAT REG32(0x40038018) -#define LM4_ADC_ADCSSPRI REG32(0x40038020) -#define LM4_ADC_ADCSPC REG32(0x40038024) -#define LM4_ADC_ADCPSSI REG32(0x40038028) -#define LM4_ADC_ADCSAC REG32(0x40038030) -#define LM4_ADC_ADCCTL REG32(0x40038038) -#define LM4_ADC_ADCCC REG32(0x40038fc8) -#define LM4_ADC_SS0_BASE 0x40038040 -#define LM4_ADC_SS1_BASE 0x40038060 -#define LM4_ADC_SS2_BASE 0x40038080 -#define LM4_ADC_SS3_BASE 0x400380a0 -#define LM4_ADC_SS_SEP 0x00000020 -static inline int lm4_adc_addr(int ss, int offset) -{ - return offset + LM4_ADC_SS0_BASE + LM4_ADC_SS_SEP * ss; -} -#define LM4ADCREG(ss, offset) REG32(lm4_adc_addr(ss, offset)) -#define LM4_ADC_SSMUX(ss) LM4ADCREG(ss, 0x000) -#define LM4_ADC_SSCTL(ss) LM4ADCREG(ss, 0x004) -#define LM4_ADC_SSFIFO(ss) LM4ADCREG(ss, 0x008) -#define LM4_ADC_SSFSTAT(ss) LM4ADCREG(ss, 0x00c) -#define LM4_ADC_SSOP(ss) LM4ADCREG(ss, 0x010) -#define LM4_ADC_SSEMUX(ss) LM4ADCREG(ss, 0x018) - -#define LM4_LPC_LPCCTL REG32(0x40080000) -#define LM4_LPC_SCI_START BIT(9) /* Start a pulse on LPC0SCI signal */ -#define LM4_LPC_SCI_CLK_1 (0 << 10) /* SCI asserted for 1 clock period */ -#define LM4_LPC_SCI_CLK_2 (1 << 10) /* SCI asserted for 2 clock periods */ -#define LM4_LPC_SCI_CLK_4 (2 << 10) /* SCI asserted for 4 clock periods */ -#define LM4_LPC_SCI_CLK_8 (3 << 10) /* SCI asserted for 8 clock periods */ -#define LM4_LPC_LPCSTS REG32(0x40080004) -#define LM4_LPC_LPCIRQCTL REG32(0x40080008) -#define LM4_LPC_LPCIRQST REG32(0x4008000c) -#define LM4_LPC_LPCIM REG32(0x40080100) -#define LM4_LPC_LPCRIS REG32(0x40080104) -#define LM4_LPC_LPCMIS REG32(0x40080108) -#define LM4_LPC_LPCIC REG32(0x4008010c) -#define LM4_LPC_INT_MASK(ch, bits) ((bits) << (4 * (ch))) -#define LM4_LPC_LPCDMACX REG32(0x40080120) -#define LM4_LPC_CH0_BASE 0x40080010 -#define LM4_LPC_CH1_BASE 0x40080020 -#define LM4_LPC_CH2_BASE 0x40080030 -#define LM4_LPC_CH3_BASE 0x40080040 -#define LM4_LPC_CH4_BASE 0x40080050 -#define LM4_LPC_CH5_BASE 0x40080060 -#define LM4_LPC_CH6_BASE 0x40080070 -#define LM4_LPC_CH7_BASE 0x40080080 -#define LM4_LPC_CH_SEP 0x00000010 -static inline int lm4_lpc_addr(int ch, int offset) -{ - return offset + LM4_LPC_CH0_BASE + LM4_LPC_CH_SEP * ch; -} -#define LM4LPCREG(ch, offset) REG32(lm4_lpc_addr(ch, offset)) -#define LM4_LPC_CTL(ch) LM4LPCREG(ch, 0x000) -#define LM4_LPC_ST(ch) LM4LPCREG(ch, 0x004) -#define LM4_LPC_ST_TOH BIT(0) /* TO Host bit */ -#define LM4_LPC_ST_FRMH BIT(1) /* FRoM Host bit */ -#define LM4_LPC_ST_CMD BIT(3) /* Last from-host byte was command */ -#define LM4_LPC_ST_BURST BIT(8) -#define LM4_LPC_ST_SCI BIT(9) -#define LM4_LPC_ST_SMI BIT(10) -#define LM4_LPC_ST_BUSY BIT(12) -#define LM4_LPC_ADR(ch) LM4LPCREG(ch, 0x008) -#define LM4_LPC_POOL_BYTES 1024 /* Size of LPCPOOL in bytes */ -#define LM4_LPC_LPCPOOL ((volatile unsigned char *)0x40080400) - -#define LM4_FAN_FANSTS REG32(0x40084000) -#define LM4_FAN_FANCTL REG32(0x40084004) -#define LM4_FAN_CH0_BASE 0x40084010 -#define LM4_FAN_CH1_BASE 0x40084020 -#define LM4_FAN_CH2_BASE 0x40084030 -#define LM4_FAN_CH3_BASE 0x40084040 -#define LM4_FAN_CH4_BASE 0x40084050 -#define LM4_FAN_CH5_BASE 0x40084060 -#define LM4_FAN_CH_SEP 0x00000010 -static inline int lm4_fan_addr(int ch, int offset) -{ - return offset + LM4_FAN_CH0_BASE + LM4_FAN_CH_SEP * ch; -} -#define LM4FANREG(ch, offset) REG32(lm4_fan_addr(ch, offset)) -#define LM4_FAN_FANCH(ch) LM4FANREG(ch, 0x000) -#define LM4_FAN_FANCMD(ch) LM4FANREG(ch, 0x004) -#define LM4_FAN_FANCST(ch) LM4FANREG(ch, 0x008) - -#define LM4_EEPROM_EESIZE REG32(0x400af000) -#define LM4_EEPROM_EEBLOCK REG32(0x400af004) -#define LM4_EEPROM_EEOFFSET REG32(0x400af008) -#define LM4_EEPROM_EERDWR REG32(0x400af010) -#define LM4_EEPROM_EERDWRINC REG32(0x400af014) -#define LM4_EEPROM_EEDONE REG32(0x400af018) -#define LM4_EEPROM_EESUPP REG32(0x400af01c) -#define LM4_EEPROM_EEUNLOCK REG32(0x400af020) -#define LM4_EEPROM_EEPROT REG32(0x400af030) -#define LM4_EEPROM_EEPASS0 REG32(0x400af034) -#define LM4_EEPROM_EEPASS1 REG32(0x400af038) -#define LM4_EEPROM_EEPASS2 REG32(0x400af03c) -#define LM4_EEPROM_EEINT REG32(0x400af040) -#define LM4_EEPROM_EEHIDE REG32(0x400af050) - -#define LM4_PECI_CTL REG32(0x400b0000) -#define LM4_PECI_DIV REG32(0x400b0004) -#define LM4_PECI_CMP REG32(0x400b0008) -#define LM4_PECI_M0D0C REG32(0x400b0010) -#define LM4_PECI_M0D1C REG32(0x400b0014) -#define LM4_PECI_M1D0C REG32(0x400b0018) -#define LM4_PECI_M1D1C REG32(0x400b001c) -#define LM4_PECI_M0D0 REG32(0x400b0040) -#define LM4_PECI_M0D1 REG32(0x400b0044) -#define LM4_PECI_M1D0 REG32(0x400b0048) -#define LM4_PECI_M1D1 REG32(0x400b004c) -#define LM4_PECI_IM REG32(0x400b0080) -#define LM4_PECI_RIS REG32(0x400b0084) -#define LM4_PECI_MIS REG32(0x400b0088) -#define LM4_PECI_IC REG32(0x400b008c) -#define LM4_PECI_ACADDR REG32(0x400b0100) -#define LM4_PECI_ACARG REG32(0x400b0104) -#define LM4_PECI_ACRDWR0 REG32(0x400b0108) -#define LM4_PECI_ACRDWR1 REG32(0x400b010c) -#define LM4_PECI_ACCMD REG32(0x400b0110) -#define LM4_PECI_ACCODE REG32(0x400b0114) - - -#define LM4_HIBERNATE_HIBRTCC REG32(0x400fc000) -#define LM4_HIBERNATE_HIBRTCM0 REG32(0x400fc004) -#define LM4_HIBERNATE_HIBRTCLD REG32(0x400fc00c) -#define LM4_HIBERNATE_HIBCTL REG32(0x400fc010) -#define LM4_HIBCTL_WRC BIT(31) -#define LM4_HIBCTL_CLK32EN BIT(6) -#define LM4_HIBCTL_PINWEN BIT(4) -#define LM4_HIBCTL_RTCWEN BIT(3) -#define LM4_HIBCTL_HIBREQ BIT(1) -#define LM4_HIBCTL_RTCEN BIT(0) -#define LM4_HIBERNATE_HIBIM REG32(0x400fc014) -#define LM4_HIBERNATE_HIBRIS REG32(0x400fc018) -#define LM4_HIBERNATE_HIBMIS REG32(0x400fc01c) -#define LM4_HIBERNATE_HIBIC REG32(0x400fc020) -#define LM4_HIBERNATE_HIBRTCT REG32(0x400fc024) -#define LM4_HIBERNATE_HIBRTCSS REG32(0x400fc028) -#define LM4_HIBERNATE_HIBDATA_ENTRIES 16 /* Number of entries in HIBDATA[] */ -#define LM4_HIBERNATE_HIBDATA ((volatile uint32_t *)0x400fc030) - -#define LM4_FLASH_FMA REG32(0x400fd000) -#define LM4_FLASH_FMD REG32(0x400fd004) -#define LM4_FLASH_FMC REG32(0x400fd008) -#define LM4_FLASH_FCRIS REG32(0x400fd00c) -#define LM4_FLASH_FCMISC REG32(0x400fd014) -#define LM4_FLASH_FMC2 REG32(0x400fd020) -#define LM4_FLASH_FWBVAL REG32(0x400fd030) -/* FWB size is 32 words = 128 bytes */ -#define LM4_FLASH_FWB ((volatile uint32_t*)0x400fd100) -#define LM4_FLASH_FSIZE REG32(0x400fdfc0) -#define LM4_FLASH_FMPRE0 REG32(0x400fe200) -#define LM4_FLASH_FMPRE1 REG32(0x400fe204) -#define LM4_FLASH_FMPRE2 REG32(0x400fe208) -#define LM4_FLASH_FMPRE3 REG32(0x400fe20c) -#define LM4_FLASH_FMPPE ((volatile uint32_t*)0x400fe400) -#define LM4_FLASH_FMPPE0 REG32(0x400fe400) -#define LM4_FLASH_FMPPE1 REG32(0x400fe404) -#define LM4_FLASH_FMPPE2 REG32(0x400fe408) -#define LM4_FLASH_FMPPE3 REG32(0x400fe40c) - -#define LM4_SYSTEM_DID0 REG32(0x400fe000) -#define LM4_SYSTEM_DID1 REG32(0x400fe004) -#define LM4_SYSTEM_PBORCTL REG32(0x400fe030) -#define LM4_SYSTEM_RIS REG32(0x400fe050) -#define LM4_SYSTEM_MISC REG32(0x400fe058) -#define LM4_SYSTEM_RESC REG32(0x400fe05c) -#define LM4_SYSTEM_RCC REG32(0x400fe060) -#define LM4_SYSTEM_RCC_ACG BIT(27) -#define LM4_SYSTEM_RCC_SYSDIV(x) (((x) & 0xf) << 23) -#define LM4_SYSTEM_RCC_USESYSDIV BIT(22) -#define LM4_SYSTEM_RCC_PWRDN BIT(13) -#define LM4_SYSTEM_RCC_BYPASS BIT(11) -#define LM4_SYSTEM_RCC_XTAL(x) (((x) & 0x1f) << 6) -#define LM4_SYSTEM_RCC_OSCSRC(x) (((x) & 0x3) << 4) -#define LM4_SYSTEM_RCC_IOSCDIS BIT(1) -#define LM4_SYSTEM_RCC_MOSCDIS BIT(0) -#define LM4_SYSTEM_RCC2 REG32(0x400fe070) -#define LM4_SYSTEM_RCC2_USERCC2 BIT(31) -#define LM4_SYSTEM_RCC2_DIV400 BIT(30) -#define LM4_SYSTEM_RCC2_SYSDIV2(x) (((x) & 0x3f) << 23) -#define LM4_SYSTEM_RCC2_SYSDIV2LSB BIT(22) -#define LM4_SYSTEM_RCC2_PWRDN2 BIT(13) -#define LM4_SYSTEM_RCC2_BYPASS2 BIT(11) -#define LM4_SYSTEM_RCC2_OSCSRC2(x) (((x) & 0x7) << 4) -#define LM4_SYSTEM_MOSCCTL REG32(0x400fe07c) -#define LM4_SYSTEM_DSLPCLKCFG REG32(0x400fe144) -#define LM4_SYSTEM_PIOSCCAL REG32(0x400fe150) -#define LM4_SYSTEM_PIOSCSTAT REG32(0x400fe154) -#define LM4_SYSTEM_PLLSTAT REG32(0x400fe168) -#define LM4_SYSTEM_SLPPWRCFG REG32(0x400fe188) -#define LM4_SYSTEM_DSLPPWRCFG REG32(0x400fe18c) -#define LM4_SYSTEM_LDOSPCTL REG32(0x400fe1b4) -#define LM4_SYSTEM_LDOSPCAL REG32(0x400fe1b8) -#define LM4_SYSTEM_LDODPCTL REG32(0x400fe1bc) -#define LM4_SYSTEM_LDODPCAL REG32(0x400fe1c0) -#define LM4_SYSTEM_SPDMST REG32(0x400fe1cc) -#define LM4_SYSTEM_BOOTCFG REG32(0x400fe1d0) -#define LM4_SYSTEM_BOOTCFG_MASK 0x7fff00ec /* Reserved bits of BOOTCFG reg */ -/* Note: USER_REG3 is used to hold pre-programming process data and should not - * be modified by EC code. See crosbug.com/p/8889. */ -#define LM4_SYSTEM_USER_REG3 REG32(0x400fe1ec) -#define LM4_SYSTEM_SRI2C REG32(0x400fe520) -#define LM4_SYSTEM_SREEPROM REG32(0x400fe558) - -#define LM4_SYSTEM_SRI2C_ADDR ((atomic_t *)0x400fe520) - -#define LM4_SYSTEM_RCGC_BASE ((volatile uint32_t *)0x400fe600) -#define LM4_SYSTEM_RCGCGPIO REG32(0x400fe608) -#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) -#define LM4_DMA_DMACTLBASE REG32(0x400ff008) -#define LM4_DMA_DMACHMAP0 REG32(0x400ff510) -#define LM4_DMA_DMACHMAP1 REG32(0x400ff514) -#define LM4_DMA_DMACHMAP2 REG32(0x400ff518) -#define LM4_DMA_DMACHMAP3 REG32(0x400ff51c) - -/* IRQ numbers */ -#define LM4_IRQ_GPIOA 0 -#define LM4_IRQ_GPIOB 1 -#define LM4_IRQ_GPIOC 2 -#define LM4_IRQ_GPIOD 3 -#define LM4_IRQ_GPIOE 4 -#define LM4_IRQ_UART0 5 -#define LM4_IRQ_UART1 6 -#define LM4_IRQ_SSI0 7 -#define LM4_IRQ_I2C0 8 -/* 9 - 13 reserved */ -#define LM4_IRQ_ADC0_SS0 14 -#define LM4_IRQ_ADC0_SS1 15 -#define LM4_IRQ_ADC0_SS2 16 -#define LM4_IRQ_ADC0_SS3 17 -#define LM4_IRQ_WATCHDOG 18 -#define LM4_IRQ_TIMER0A 19 -#define LM4_IRQ_TIMER0B 20 -#define LM4_IRQ_TIMER1A 21 -#define LM4_IRQ_TIMER1B 22 -#define LM4_IRQ_TIMER2A 23 -#define LM4_IRQ_TIMER2B 24 -#define LM4_IRQ_ACMP0 25 -#define LM4_IRQ_ACMP1 26 -#define LM4_IRQ_ACMP2 27 -#define LM4_IRQ_SYSCTRL 28 -#define LM4_IRQ_EEPROM 29 -#define LM4_IRQ_GPIOF 30 -#define LM4_IRQ_GPIOG 31 -#define LM4_IRQ_GPIOH 32 -#define LM4_IRQ_UART2 33 -#define LM4_IRQ_SSI1 34 -#define LM4_IRQ_TIMER3A 35 -#define LM4_IRQ_TIMER3B 36 -#define LM4_IRQ_I2C1 37 -/* 38 - 42 reserved */ -#define LM4_IRQ_HIBERNATE 43 -/* 44 - 45 reserved */ -#define LM4_IRQ_UDMA_SOFTWARE 46 -#define LM4_IRQ_UDMA_ERROR 47 -#define LM4_IRQ_ADC1_SS0 48 -#define LM4_IRQ_ADC1_SS1 49 -#define LM4_IRQ_ADC1_SS2 50 -#define LM4_IRQ_ADC1_SS3 51 -/* 52 - 53 reserved */ -#define LM4_IRQ_GPIOJ 54 -#define LM4_IRQ_GPIOK 55 -#define LM4_IRQ_GPIOL 56 -#define LM4_IRQ_SSI2 57 -#define LM4_IRQ_SSI3 58 -#define LM4_IRQ_UART3 59 -#define LM4_IRQ_UART4 60 -#define LM4_IRQ_UART5 61 -#define LM4_IRQ_UART6 62 -#define LM4_IRQ_UART7 63 -/* 64 - 67 reserved */ -#define LM4_IRQ_I2C2 68 -#define LM4_IRQ_I2C3 69 -#define LM4_IRQ_TIMER4A 70 -#define LM4_IRQ_TIMER4B 71 -/* 72 - 91 reserved */ -#define LM4_IRQ_TIMER5A 92 -#define LM4_IRQ_TIMER5B 93 -#define LM4_IRQ_TIMERW0A 94 -#define LM4_IRQ_TIMERW0B 95 -#define LM4_IRQ_TIMERW1A 96 -#define LM4_IRQ_TIMERW1B 97 -#define LM4_IRQ_TIMERW2A 98 -#define LM4_IRQ_TIMERW2B 99 -#define LM4_IRQ_TIMERW3A 100 -#define LM4_IRQ_TIMERW3B 101 -#define LM4_IRQ_TIMERW4A 102 -#define LM4_IRQ_TIMERW4B 103 -#define LM4_IRQ_TIMERW5A 104 -#define LM4_IRQ_TIMERW5B 105 -#define LM4_IRQ_SYS_EXCEPTION 106 -#define LM4_IRQ_SYS_PECI 107 -#define LM4_IRQ_LPC 108 -#define LM4_IRQ_I2C4 109 -#define LM4_IRQ_I2C5 110 -#define LM4_IRQ_GPIOM 111 -#define LM4_IRQ_GPION 112 -/* 113 reserved */ -#define LM4_IRQ_FAN 114 -/* 115 reserved */ -#define LM4_IRQ_GPIOP 116 -#define LM4_IRQ_GPIOP1 117 -#define LM4_IRQ_GPIOP2 118 -#define LM4_IRQ_GPIOP3 119 -#define LM4_IRQ_GPIOP4 120 -#define LM4_IRQ_GPIOP5 121 -#define LM4_IRQ_GPIOP6 122 -#define LM4_IRQ_GPIOP7 123 -#define LM4_IRQ_GPIOQ 124 -#define LM4_IRQ_GPIOQ1 125 -#define LM4_IRQ_GPIOQ2 126 -#define LM4_IRQ_GPIOQ3 127 -#define LM4_IRQ_GPIOQ4 128 -#define LM4_IRQ_GPIOQ5 129 -#define LM4_IRQ_GPIOQ6 130 -#define LM4_IRQ_GPIOQ7 131 -/* 132 - 138 reserved */ - -/* GPIO */ -#define LM4_GPIO_PORTA_BASE 0x40004000 -#define LM4_GPIO_PORTB_BASE 0x40005000 -#define LM4_GPIO_PORTC_BASE 0x40006000 -#define LM4_GPIO_PORTD_BASE 0x40007000 -#define LM4_GPIO_PORTE_BASE 0x40024000 -#define LM4_GPIO_PORTF_BASE 0x40025000 -#define LM4_GPIO_PORTG_BASE 0x40026000 -#define LM4_GPIO_PORTH_BASE 0x40027000 -#define LM4_GPIO_PORTJ_BASE 0x4003d000 -#define LM4_GPIO_PORTK_BASE 0x40061000 -#define LM4_GPIO_PORTL_BASE 0x40062000 -#define LM4_GPIO_PORTM_BASE 0x40063000 -#define LM4_GPIO_PORTN_BASE 0x40064000 -#define LM4_GPIO_PORTP_BASE 0x40065000 -#define LM4_GPIO_PORTQ_BASE 0x40066000 -#define LM4_GPIO_PORTA_AHB_BASE 0x40058000 -#define LM4_GPIO_PORTB_AHB_BASE 0x40059000 -#define LM4_GPIO_PORTC_AHB_BASE 0x4005a000 -#define LM4_GPIO_PORTD_AHB_BASE 0x4005b000 -#define LM4_GPIO_PORTE_AHB_BASE 0x4005c000 -#define LM4_GPIO_PORTF_AHB_BASE 0x4005d000 -#define LM4_GPIO_PORTG_AHB_BASE 0x4005e000 -#define LM4_GPIO_PORTH_AHB_BASE 0x4005f000 -#define LM4_GPIO_PORTJ_AHB_BASE 0x40060000 -/* Ports for passing to LM4GPIOREG(); abstracted from base addresses above so - * that we can switch to/from AHB. */ -#define LM4_GPIO_A LM4_GPIO_PORTA_BASE -#define LM4_GPIO_B LM4_GPIO_PORTB_BASE -#define LM4_GPIO_C LM4_GPIO_PORTC_BASE -#define LM4_GPIO_D LM4_GPIO_PORTD_BASE -#define LM4_GPIO_E LM4_GPIO_PORTE_BASE -#define LM4_GPIO_F LM4_GPIO_PORTF_BASE -#define LM4_GPIO_G LM4_GPIO_PORTG_BASE -#define LM4_GPIO_H LM4_GPIO_PORTH_BASE -#define LM4_GPIO_J LM4_GPIO_PORTJ_BASE -#define LM4_GPIO_K LM4_GPIO_PORTK_BASE -#define LM4_GPIO_L LM4_GPIO_PORTL_BASE -#define LM4_GPIO_M LM4_GPIO_PORTM_BASE -#define LM4_GPIO_N LM4_GPIO_PORTN_BASE -#define LM4_GPIO_P LM4_GPIO_PORTP_BASE -#define LM4_GPIO_Q LM4_GPIO_PORTQ_BASE -#define LM4GPIOREG(port, offset) REG32((port) + (offset)) -#define LM4_GPIO_DATA(port, mask) LM4GPIOREG(port, ((mask) << 2)) -#define LM4_GPIO_DIR(port) LM4GPIOREG(port, 0x400) -#define LM4_GPIO_IS(port) LM4GPIOREG(port, 0x404) -#define LM4_GPIO_IBE(port) LM4GPIOREG(port, 0x408) -#define LM4_GPIO_IEV(port) LM4GPIOREG(port, 0x40c) -#define LM4_GPIO_IM(port) LM4GPIOREG(port, 0x410) -#define LM4_GPIO_RIS(port) LM4GPIOREG(port, 0x414) -#define LM4_GPIO_MIS(port) LM4GPIOREG(port, 0x418) -#define LM4_GPIO_ICR(port) LM4GPIOREG(port, 0x41c) -#define LM4_GPIO_AFSEL(port) LM4GPIOREG(port, 0x420) -#define LM4_GPIO_DR2R(port) LM4GPIOREG(port, 0x500) -#define LM4_GPIO_DR4R(port) LM4GPIOREG(port, 0x504) -#define LM4_GPIO_DR8R(port) LM4GPIOREG(port, 0x508) -#define LM4_GPIO_ODR(port) LM4GPIOREG(port, 0x50c) -#define LM4_GPIO_PUR(port) LM4GPIOREG(port, 0x510) -#define LM4_GPIO_PDR(port) LM4GPIOREG(port, 0x514) -#define LM4_GPIO_SLR(port) LM4GPIOREG(port, 0x518) -#define LM4_GPIO_DEN(port) LM4GPIOREG(port, 0x51c) -#define LM4_GPIO_LOCK(port) LM4GPIOREG(port, 0x520) -#define LM4_GPIO_CR(port) LM4GPIOREG(port, 0x524) -#define LM4_GPIO_AMSEL(port) LM4GPIOREG(port, 0x528) -#define LM4_GPIO_PCTL(port) LM4GPIOREG(port, 0x52c) - -/* Chip-independent aliases for port base addresses */ -#define GPIO_A LM4_GPIO_A -#define GPIO_B LM4_GPIO_B -#define GPIO_C LM4_GPIO_C -#define GPIO_D LM4_GPIO_D -#define GPIO_E LM4_GPIO_E -#define GPIO_F LM4_GPIO_F -#define GPIO_G LM4_GPIO_G -#define GPIO_H LM4_GPIO_H -#define GPIO_J LM4_GPIO_J -#define GPIO_K LM4_GPIO_K -#define GPIO_L LM4_GPIO_L -#define GPIO_M LM4_GPIO_M -#define GPIO_N LM4_GPIO_N -#define GPIO_P LM4_GPIO_P -#define GPIO_Q LM4_GPIO_Q - -#define UNIMPLEMENTED_GPIO_BANK GPIO_A - -/* Value to write to LM4_GPIO_LOCK to unlock writes */ -#define LM4_GPIO_LOCK_UNLOCK 0x4c4f434b - -/* I2C */ -#define LM4_I2C0_BASE 0x40020000 -#define LM4_I2C1_BASE 0x40021000 -#define LM4_I2C2_BASE 0x40022000 -#define LM4_I2C3_BASE 0x40023000 -#define LM4_I2C4_BASE 0x400c0000 -#define LM4_I2C5_BASE 0x400c1000 -#define LM4_I2C_BASESEP 0x00001000 -/* I2C base address by port. Compiles to a constant in gcc if port - and offset are constant. */ -static inline int lm4_i2c_addr(int port, int offset) -{ - return offset + (port < 4 ? - LM4_I2C0_BASE + LM4_I2C_BASESEP * port : - LM4_I2C4_BASE + LM4_I2C_BASESEP * (port - 4)); -} -#define LM4I2CREG(port, offset) REG32(lm4_i2c_addr(port, offset)) -#define LM4_I2C_MSA(port) LM4I2CREG(port, 0x000) -#define LM4_I2C_MCS(port) LM4I2CREG(port, 0x004) -#define LM4_I2C_MDR(port) LM4I2CREG(port, 0x008) -#define LM4_I2C_MTPR(port) LM4I2CREG(port, 0x00c) -#define LM4_I2C_MIMR(port) LM4I2CREG(port, 0x010) -#define LM4_I2C_MRIS(port) LM4I2CREG(port, 0x014) -#define LM4_I2C_MMIS(port) LM4I2CREG(port, 0x018) -#define LM4_I2C_MICR(port) LM4I2CREG(port, 0x01c) -#define LM4_I2C_MCR(port) LM4I2CREG(port, 0x020) -#define LM4_I2C_MCLKOCNT(port) LM4I2CREG(port, 0x024) -#define LM4_I2C_MBMON(port) LM4I2CREG(port, 0x02c) - - -/* Timers */ -/* Timers 0-5 are 16/32 bit */ -#define LM4_TIMER0_BASE 0x40030000 -#define LM4_TIMER1_BASE 0x40031000 -#define LM4_TIMER2_BASE 0x40032000 -#define LM4_TIMER3_BASE 0x40033000 -#define LM4_TIMER4_BASE 0x40034000 -#define LM4_TIMER5_BASE 0x40035000 -/* Timers 6-11 are 32/64 bit */ -#define LM4_TIMERW0_BASE 0x40036000 -#define LM4_TIMERW1_BASE 0x40037000 -#define LM4_TIMERW2_BASE 0x4004c000 -#define LM4_TIMERW3_BASE 0x4004d000 -#define LM4_TIMERW4_BASE 0x4004e000 -#define LM4_TIMERW5_BASE 0x4004f000 -#define LM4_TIMER_SEP 0x00001000 -static inline int lm4_timer_addr(int timer, int offset) -{ - if (timer < 8) - return offset + LM4_TIMER0_BASE + LM4_TIMER_SEP * timer; - else - return offset + LM4_TIMERW2_BASE + LM4_TIMER_SEP * (timer - 8); -} -#define LM4TIMERREG(timer, offset) REG32(lm4_timer_addr(timer, offset)) -#define LM4_TIMER_CFG(tmr) LM4TIMERREG(tmr, 0x00) -#define LM4_TIMER_TAMR(tmr) LM4TIMERREG(tmr, 0x04) -#define LM4_TIMER_TBMR(tmr) LM4TIMERREG(tmr, 0x08) -#define LM4_TIMER_CTL(tmr) LM4TIMERREG(tmr, 0x0c) -#define LM4_TIMER_SYNC(tmr) LM4TIMERREG(tmr, 0x10) -#define LM4_TIMER_IMR(tmr) LM4TIMERREG(tmr, 0x18) -#define LM4_TIMER_RIS(tmr) LM4TIMERREG(tmr, 0x1c) -#define LM4_TIMER_MIS(tmr) LM4TIMERREG(tmr, 0x20) -#define LM4_TIMER_ICR(tmr) LM4TIMERREG(tmr, 0x24) -#define LM4_TIMER_TAILR(tmr) LM4TIMERREG(tmr, 0x28) -#define LM4_TIMER_TBILR(tmr) LM4TIMERREG(tmr, 0x2c) -#define LM4_TIMER_TAMATCHR(tmr) LM4TIMERREG(tmr, 0x30) -#define LM4_TIMER_TBMATCHR(tmr) LM4TIMERREG(tmr, 0x34) -#define LM4_TIMER_TAPR(tmr) LM4TIMERREG(tmr, 0x38) -#define LM4_TIMER_TBPR(tmr) LM4TIMERREG(tmr, 0x3c) -#define LM4_TIMER_TAPMR(tmr) LM4TIMERREG(tmr, 0x40) -#define LM4_TIMER_TBPMR(tmr) LM4TIMERREG(tmr, 0x44) -#define LM4_TIMER_TAR(tmr) LM4TIMERREG(tmr, 0x48) -#define LM4_TIMER_TBR(tmr) LM4TIMERREG(tmr, 0x4c) -#define LM4_TIMER_TAV(tmr) LM4TIMERREG(tmr, 0x50) -#define LM4_TIMER_TBV(tmr) LM4TIMERREG(tmr, 0x54) -#define LM4_TIMER_RTCPD(tmr) LM4TIMERREG(tmr, 0x58) -#define LM4_TIMER_TAPS(tmr) LM4TIMERREG(tmr, 0x5c) -#define LM4_TIMER_TBPS(tmr) LM4TIMERREG(tmr, 0x60) -#define LM4_TIMER_TAPV(tmr) LM4TIMERREG(tmr, 0x64) -#define LM4_TIMER_TBPV(tmr) LM4TIMERREG(tmr, 0x68) - -#define LM4_SYSTICK_CTRL REG32(0xe000e010) -#define LM4_SYSTICK_RELOAD REG32(0xe000e014) -#define LM4_SYSTICK_CURRENT REG32(0xe000e018) - -/* Watchdogs */ -#define LM4_WATCHDOG0_BASE 0x40000000 -#define LM4_WATCHDOG1_BASE 0x40001000 -static inline int lm4_watchdog_addr(int num, int offset) -{ - return offset + (num ? LM4_WATCHDOG1_BASE : LM4_WATCHDOG0_BASE); -} -#define LM4WDTREG(num, offset) REG32(lm4_watchdog_addr(num, offset)) -#define LM4_WATCHDOG_LOAD(n) LM4WDTREG(n, 0x000) -#define LM4_WATCHDOG_VALUE(n) LM4WDTREG(n, 0x004) -#define LM4_WATCHDOG_CTL(n) LM4WDTREG(n, 0x008) -#define LM4_WATCHDOG_ICR(n) LM4WDTREG(n, 0x00c) -#define LM4_WATCHDOG_RIS(n) LM4WDTREG(n, 0x010) -#define LM4_WATCHDOG_TEST(n) LM4WDTREG(n, 0x418) -#define LM4_WATCHDOG_LOCK(n) LM4WDTREG(n, 0xc00) - -#define LM4_TEST_MODE_ENABLED REG32(0x400fdff0) - -#endif /* __CROS_EC_REGISTERS_H */ diff --git a/chip/lm4/spi.c b/chip/lm4/spi.c deleted file mode 100644 index 629e306af7..0000000000 --- a/chip/lm4/spi.c +++ /dev/null @@ -1,179 +0,0 @@ -/* Copyright 2013 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. - */ - -/* SPI module for Chrome EC */ - -#include "console.h" -#include "gpio.h" -#include "hooks.h" -#include "registers.h" -#include "spi.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_SPI, outstr) -#define CPRINTS(format, args...) cprints(CC_SPI, format, ## args) - -int spi_enable(const struct spi_device_t *spi_device, int enable) -{ - if (enable) { - gpio_config_module(MODULE_SPI, 1); - /* - * Don't use the SSI0 frame output. - * CS# is a GPIO so we can keep it low during an entire - * transaction. - */ - gpio_set_flags(spi_device->gpio_cs, GPIO_OUTPUT); - gpio_set_level(spi_device->gpio_cs, 1); - - /* Enable SSI port */ - LM4_SSI_CR1(0) |= 0x02; - } else { - /* Disable SSI port */ - LM4_SSI_CR1(0) &= ~0x02; - - /* Make sure CS# is deselected */ - gpio_set_level(spi_device->gpio_cs, 1); - gpio_set_flags(spi_device->gpio_cs[i], GPIO_ODR_HIGH); - - gpio_config_module(MODULE_SPI, 0); - } - - return EC_SUCCESS; -} - - -int spi_transaction(const struct spi_device_t *spi_device, - const uint8_t *txdata, int txlen, - uint8_t *rxdata, int rxlen) -{ - int totallen = txlen + rxlen; - int txcount = 0, rxcount = 0; - static struct mutex spi_mutex; - volatile uint32_t unused __attribute__((unused)); - - mutex_lock(&spi_mutex); - /* Empty the receive FIFO */ - while (LM4_SSI_SR(0) & LM4_SSI_SR_RNE) - unused = LM4_SSI_DR(0); - - /* Start transaction. Need to do this explicitly because the LM4 - * SSI controller pulses its frame select every byte, and the EEPROM - * wants the chip select held low during the entire transaction. */ - gpio_set_level(spi_device->gpio_cs, 0); - - while (rxcount < totallen) { - /* Handle received bytes if any. We just checked rxcount < - * totallen, so we don't need to worry about overflowing the - * receive buffer. */ - if (LM4_SSI_SR(0) & LM4_SSI_SR_RNE) { - if (rxcount < txlen) { - /* Throw away bytes received while we were - transmitting */ - unused = LM4_SSI_DR(0); - } else - *(rxdata++) = LM4_SSI_DR(0); - rxcount++; - } - - /* Transmit another byte if needed */ - if ((LM4_SSI_SR(0) & LM4_SSI_SR_TNF) && txcount < totallen) { - if (txcount < txlen) - LM4_SSI_DR(0) = *(txdata++); - else { - /* Clock out unused byte so we can clock in the - * response byte */ - LM4_SSI_DR(0) = 0; - } - txcount++; - } - } - - /* End transaction */ - gpio_set_level(spi_device->gpio_cs, 1); - mutex_unlock(&spi_mutex); - - return EC_SUCCESS; -} - -/*****************************************************************************/ -/* Hooks */ - -static int spi_init(void) -{ - /* 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 */ - - /* Use PIOSC for clock. This limits us to 8MHz (PIOSC/2), but is - * simpler to configure and we don't need to worry about clock - * frequency changing when the PLL is disabled. If we really start - * using this, might be worth using the system clock and handling - * frequency change (like we do with PECI) so we can go faster. */ - LM4_SSI_CC(0) = 1; - /* SSICLK = PIOSC / (CPSDVSR * (1 + SCR) - * = 16 MHz / (2 * (1 + 0)) - * = 8 MHz */ - LM4_SSI_CPSR(0) = 2; - - /* Ensure the SPI port is disabled. This keeps us from interfering - * with the main chipset when we're not explicitly using the SPI - * bus. */ - spi_enable(SPI_FLASH_DEVICE, 0); - - return EC_SUCCESS; -} -DECLARE_HOOK(HOOK_INIT, spi_init, HOOK_PRIO_INIT_SPI); - -/*****************************************************************************/ -/* Console commands */ - -static int printrx(const char *desc, const uint8_t *txdata, int txlen, - int rxlen) -{ - uint8_t rxdata[32]; - int rv; - int i; - - rv = spi_transaction(SPI_FLASH_DEVICE, txdata, txlen, rxdata, rxlen); - if (rv) - return rv; - - ccprintf("%-12s:", desc); - for (i = 0; i < rxlen; i++) - ccprintf(" 0x%02x", rxdata[i]); - ccputs("\n"); - return EC_SUCCESS; -} - - -static int command_spirom(int argc, char **argv) -{ - uint8_t txmandev[] = {0x90, 0x00, 0x00, 0x00}; - uint8_t txjedec[] = {0x9f}; - uint8_t txunique[] = {0x4b, 0x00, 0x00, 0x00, 0x00}; - uint8_t txsr1[] = {0x05}; - uint8_t txsr2[] = {0x35}; - - spi_enable(SPI_FLASH_DEVICE, 1); - - printrx("Man/Dev ID", txmandev, sizeof(txmandev), 2); - printrx("JEDEC ID", txjedec, sizeof(txjedec), 3); - printrx("Unique ID", txunique, sizeof(txunique), 8); - printrx("Status reg 1", txsr1, sizeof(txsr1), 1); - printrx("Status reg 2", txsr2, sizeof(txsr2), 1); - - spi_enable(SPI_FLASH_DEVICE, 0); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(spirom, command_spirom, - NULL, - "Test reading SPI EEPROM"); diff --git a/chip/lm4/system.c b/chip/lm4/system.c deleted file mode 100644 index e4480de01d..0000000000 --- a/chip/lm4/system.c +++ /dev/null @@ -1,776 +0,0 @@ -/* Copyright 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. - */ - -/* System module for Chrome EC : LM4 hardware specific implementation */ - -#include "clock.h" -#include "common.h" -#include "console.h" -#include "cpu.h" -#include "host_command.h" -#include "panic.h" -#include "registers.h" -#include "system.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -/* Indices for hibernate data registers */ -enum hibdata_index { - HIBDATA_INDEX_SCRATCHPAD, /* General-purpose scratchpad */ - HIBDATA_INDEX_WAKE, /* Wake reasons for hibernate */ - HIBDATA_INDEX_SAVED_RESET_FLAGS, /* Saved reset flags */ -#ifdef CONFIG_SOFTWARE_PANIC - HIBDATA_INDEX_SAVED_PANIC_REASON, /* Saved panic reason */ - HIBDATA_INDEX_SAVED_PANIC_INFO, /* Saved panic data */ - HIBDATA_INDEX_SAVED_PANIC_EXCEPTION,/* Saved panic exception code */ - HIBDATA_INDEX_SAVED_PANIC_FLAGS, /* Saved panic flags */ -#endif -}; - -/* Flags for HIBDATA_INDEX_WAKE */ -#define HIBDATA_WAKE_RTC BIT(0) /* RTC alarm */ -#define HIBDATA_WAKE_HARD_RESET BIT(1) /* Hard reset via short RTC alarm */ -#define HIBDATA_WAKE_PIN BIT(2) /* Wake pin */ - -/* - * Time to hibernate to trigger a power-on reset. 50 ms is sufficient for the - * EC itself, but we need a longer delay to ensure the rest of the components - * on the same power rail are reset and 5VALW has dropped. - */ -#define HIB_RESET_USEC 1000000 - -/* - * Convert between microseconds and the hibernation module RTC subsecond - * register which has 15-bit resolution. Divide down both numerator and - * denominator to avoid integer overflow while keeping the math accurate. - */ -#define HIB_RTC_USEC_TO_SUBSEC(us) ((us) * (32768/64) / (1000000/64)) -#define HIB_RTC_SUBSEC_TO_USEC(ss) ((ss) * (1000000/64) / (32768/64)) - -/** - * Wait for a write to commit to a hibernate register. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -static int wait_for_hibctl_wc(void) -{ - int i; - - /* Wait for write-capable */ - for (i = 0; i < 1000000; i++) { - if (LM4_HIBERNATE_HIBCTL & LM4_HIBCTL_WRC) - return EC_SUCCESS; - } - return EC_ERROR_TIMEOUT; -} - -/** - * Read hibernate register at specified index. - * - * @return The value of the register or 0 if invalid index. - */ -static uint32_t hibdata_read(enum hibdata_index index) -{ - if (index < 0 || index >= LM4_HIBERNATE_HIBDATA_ENTRIES) - return 0; - - return LM4_HIBERNATE_HIBDATA[index]; -} - -/** - * Write hibernate register at specified index. - * - * @return nonzero if error. - */ -static int hibdata_write(enum hibdata_index index, uint32_t value) -{ - int rv; - - if (index < 0 || index >= LM4_HIBERNATE_HIBDATA_ENTRIES) - return EC_ERROR_INVAL; - - /* Wait for ok-to-write */ - rv = wait_for_hibctl_wc(); - if (rv != EC_SUCCESS) - return rv; - - /* Write register */ - LM4_HIBERNATE_HIBDATA[index] = value; - - /* Wait for write-complete */ - return wait_for_hibctl_wc(); -} - -uint32_t chip_read_reset_flags(void) -{ - return hibdata_read(HIBDATA_INDEX_SAVED_RESET_FLAGS); -} - -void chip_save_reset_flags(uint32_t flags) -{ - hibdata_write(HIBDATA_INDEX_SAVED_RESET_FLAGS, flags); -} - -static void check_reset_cause(void) -{ - uint32_t hib_status = LM4_HIBERNATE_HIBRIS; - uint32_t raw_reset_cause = LM4_SYSTEM_RESC; - uint32_t hib_wake_flags = hibdata_read(HIBDATA_INDEX_WAKE); - uint32_t flags = 0; - - /* Clear the reset causes now that we've read them */ - LM4_SYSTEM_RESC = 0; - wait_for_hibctl_wc(); - LM4_HIBERNATE_HIBIC = hib_status; - hibdata_write(HIBDATA_INDEX_WAKE, 0); - - if (raw_reset_cause & 0x02) { - /* - * Full power-on reset of chip. This resets the flash - * protection registers to their permanently-stored values. - * Note that this is also triggered by hibernation, because - * that de-powers the chip. - */ - flags |= EC_RESET_FLAG_POWER_ON; - } else if (!flags && (raw_reset_cause & 0x01)) { - /* - * LM4 signals the reset pin in RESC for all power-on resets, - * even though the external pin wasn't asserted. Make setting - * this flag mutually-exclusive with power on flag, so we can - * use it to indicate a keyboard-triggered reset. - */ - flags |= EC_RESET_FLAG_RESET_PIN; - } - - if (raw_reset_cause & 0x04) - flags |= EC_RESET_FLAG_BROWNOUT; - - if (raw_reset_cause & 0x10) - flags |= EC_RESET_FLAG_SOFT; - - if (raw_reset_cause & 0x28) { - /* Watchdog timer 0 or 1 */ - flags |= EC_RESET_FLAG_WATCHDOG; - } - - /* Handle other raw reset causes */ - if (raw_reset_cause && !flags) - flags |= EC_RESET_FLAG_OTHER; - - - if ((hib_status & 0x09) && - (hib_wake_flags & HIBDATA_WAKE_HARD_RESET)) { - /* Hibernation caused by software-triggered hard reset */ - flags |= EC_RESET_FLAG_HARD; - - /* Consume the hibernate reasons so we don't see them below */ - hib_status &= ~0x09; - } - - if ((hib_status & 0x01) && (hib_wake_flags & HIBDATA_WAKE_RTC)) - flags |= EC_RESET_FLAG_RTC_ALARM; - - if ((hib_status & 0x08) && (hib_wake_flags & HIBDATA_WAKE_PIN)) - flags |= EC_RESET_FLAG_WAKE_PIN; - - if (hib_status & 0x04) - flags |= EC_RESET_FLAG_LOW_BATTERY; - - /* Restore then clear saved reset flags */ - flags |= chip_read_reset_flags(); - chip_save_reset_flags(0); - - system_set_reset_flags(flags); -} - -/* - * A3 and earlier chip stepping has a problem accessing flash during shutdown. - * To work around that, we jump to RAM before hibernating. This function must - * live in RAM. It must be called with interrupts disabled, cannot call other - * functions, and can't be declared static (or else the compiler optimizes it - * into the main hibernate function. - */ -void __attribute__((noinline)) __attribute__((section(".iram.text"))) -__enter_hibernate(int hibctl) -{ - LM4_HIBERNATE_HIBCTL = hibctl; - while (1) - ; -} - -/** - * Read the real-time clock. - * - * @param ss_ptr Destination for sub-seconds value, if not null. - * - * @return the real-time clock seconds value. - */ -uint32_t system_get_rtc_sec_subsec(uint32_t *ss_ptr) -{ - uint32_t rtc, rtc2; - uint32_t rtcss, rtcss2; - - /* - * The hibernate module isn't synchronized, so need to read repeatedly - * to guarantee a valid read. - */ - do { - rtc = LM4_HIBERNATE_HIBRTCC; - rtcss = LM4_HIBERNATE_HIBRTCSS & 0x7fff; - rtcss2 = LM4_HIBERNATE_HIBRTCSS & 0x7fff; - rtc2 = LM4_HIBERNATE_HIBRTCC; - } while (rtc != rtc2 || rtcss != rtcss2); - - if (ss_ptr) - *ss_ptr = rtcss; - - return rtc; -} - -timestamp_t system_get_rtc(void) -{ - uint32_t rtc, rtc_ss; - timestamp_t time; - - rtc = system_get_rtc_sec_subsec(&rtc_ss); - - time.val = ((uint64_t)rtc) * SECOND + HIB_RTC_SUBSEC_TO_USEC(rtc_ss); - return time; -} - -/** - * Set the real-time clock. - * - * @param seconds New clock value. - */ -void system_set_rtc(uint32_t seconds) -{ - wait_for_hibctl_wc(); - LM4_HIBERNATE_HIBRTCLD = seconds; - wait_for_hibctl_wc(); -} - -/** - * Set the hibernate RTC match time at a given time from now - * - * @param seconds Number of seconds from now for RTC match - * @param microseconds Number of microseconds from now for RTC match - */ -static void set_hibernate_rtc_match_time(uint32_t seconds, - uint32_t microseconds) -{ - uint32_t rtc, rtcss; - - /* - * Make sure that the requested delay is not less then the - * amount of time it takes to set the RTC match registers, - * otherwise, the match event could be missed. - */ - if (seconds == 0 && microseconds < HIB_SET_RTC_MATCH_DELAY_USEC) - microseconds = HIB_SET_RTC_MATCH_DELAY_USEC; - - /* Calculate the wake match */ - rtc = system_get_rtc_sec_subsec(&rtcss) + seconds; - rtcss += HIB_RTC_USEC_TO_SUBSEC(microseconds); - if (rtcss > 0x7fff) { - rtc += rtcss >> 15; - rtcss &= 0x7fff; - } - - /* Set RTC alarm match */ - wait_for_hibctl_wc(); - LM4_HIBERNATE_HIBRTCM0 = rtc; - wait_for_hibctl_wc(); - LM4_HIBERNATE_HIBRTCSS = rtcss << 16; - wait_for_hibctl_wc(); -} - -/** - * Use hibernate module to set up an RTC interrupt at a given - * time from now - * - * @param seconds Number of seconds before RTC interrupt - * @param microseconds Number of microseconds before RTC interrupt - */ -void system_set_rtc_alarm(uint32_t seconds, uint32_t microseconds) -{ - /* Clear pending interrupt */ - wait_for_hibctl_wc(); - LM4_HIBERNATE_HIBIC = LM4_HIBERNATE_HIBRIS; - - /* Set match time */ - set_hibernate_rtc_match_time(seconds, microseconds); - - /* Enable RTC interrupt on match */ - wait_for_hibctl_wc(); - LM4_HIBERNATE_HIBIM = 1; - - /* - * Wait for the write to commit. This ensures that the RTC interrupt - * actually gets enabled. This is important if we're about to switch - * the system to the 30 kHz oscillator, which might prevent the write - * from committing. - */ - wait_for_hibctl_wc(); -} - -/** - * Disable and clear the RTC interrupt. - */ -void system_reset_rtc_alarm(void) -{ - /* Disable hibernate interrupts */ - wait_for_hibctl_wc(); - LM4_HIBERNATE_HIBIM = 0; - - /* Clear interrupts */ - wait_for_hibctl_wc(); - LM4_HIBERNATE_HIBIC = LM4_HIBERNATE_HIBRIS; -} - -/** - * Hibernate module interrupt - */ -static void __hibernate_irq(void) -{ - system_reset_rtc_alarm(); -} -DECLARE_IRQ(LM4_IRQ_HIBERNATE, __hibernate_irq, 1); - -/** - * Enable hibernate interrupt - */ -void system_enable_hib_interrupt(void) -{ - task_enable_irq(LM4_IRQ_HIBERNATE); -} - -/** - * Internal hibernate function. - * - * @param seconds Number of seconds to sleep before RTC alarm - * @param microseconds Number of microseconds to sleep before RTC alarm - * @param flags Additional hibernate wake flags - */ -static void hibernate(uint32_t seconds, uint32_t microseconds, uint32_t flags) -{ - uint32_t hibctl; - - /* Set up wake reasons and hibernate flags */ - hibctl = LM4_HIBERNATE_HIBCTL | LM4_HIBCTL_PINWEN; - - if (flags & HIBDATA_WAKE_PIN) - hibctl |= LM4_HIBCTL_PINWEN; - else - hibctl &= ~LM4_HIBCTL_PINWEN; - - if (seconds || microseconds) { - hibctl |= LM4_HIBCTL_RTCWEN; - flags |= HIBDATA_WAKE_RTC; - - set_hibernate_rtc_match_time(seconds, microseconds); - - /* Enable RTC interrupt on match */ - wait_for_hibctl_wc(); - LM4_HIBERNATE_HIBIM = 1; - } else { - hibctl &= ~LM4_HIBCTL_RTCWEN; - } - wait_for_hibctl_wc(); - LM4_HIBERNATE_HIBCTL = hibctl; - - /* Clear pending interrupt */ - wait_for_hibctl_wc(); - LM4_HIBERNATE_HIBIC = LM4_HIBERNATE_HIBRIS; - - /* Store hibernate flags */ - hibdata_write(HIBDATA_INDEX_WAKE, flags); - - __enter_hibernate(hibctl | LM4_HIBCTL_HIBREQ); -} - -void system_hibernate(uint32_t seconds, uint32_t microseconds) -{ - /* Flush console before hibernating */ - cflush(); - hibernate(seconds, microseconds, HIBDATA_WAKE_PIN); -} - -void chip_pre_init(void) -{ - /* Enable clocks to GPIO block C in run and sleep modes. */ - clock_enable_peripheral(CGC_OFFSET_GPIO, 0x0004, CGC_MODE_ALL); - - /* - * Ensure PC0:3 are set to JTAG function. They should be set this way - * on a cold boot, but on a warm reboot a previous misbehaving image - * could have set them differently. - */ - if (((LM4_GPIO_PCTL(LM4_GPIO_C) & 0x0000ffff) == 0x00001111) && - ((LM4_GPIO_AFSEL(LM4_GPIO_C) & 0x0f) == 0x0f) && - ((LM4_GPIO_DEN(LM4_GPIO_C) & 0x0f) == 0x0f) && - ((LM4_GPIO_PUR(LM4_GPIO_C) & 0x0f) == 0x0f)) - return; /* Already properly configured */ - - /* Unlock commit register for JTAG pins */ - LM4_GPIO_LOCK(LM4_GPIO_C) = LM4_GPIO_LOCK_UNLOCK; - LM4_GPIO_CR(LM4_GPIO_C) |= 0x0f; - - /* Reset JTAG pins */ - LM4_GPIO_PCTL(LM4_GPIO_C) = - (LM4_GPIO_PCTL(LM4_GPIO_C) & 0xffff0000) | 0x00001111; - LM4_GPIO_AFSEL(LM4_GPIO_C) |= 0x0f; - LM4_GPIO_DEN(LM4_GPIO_C) |= 0x0f; - LM4_GPIO_PUR(LM4_GPIO_C) |= 0x0f; - - /* Set interrupt on either edge of the JTAG signals */ - LM4_GPIO_IS(LM4_GPIO_C) &= ~0x0f; - LM4_GPIO_IBE(LM4_GPIO_C) |= 0x0f; - - /* Re-lock commit register */ - LM4_GPIO_CR(LM4_GPIO_C) &= ~0x0f; - LM4_GPIO_LOCK(LM4_GPIO_C) = 0; -} - -void system_pre_init(void) -{ - uint32_t hibctl; -#ifdef CONFIG_SOFTWARE_PANIC - uint32_t reason, info; - uint8_t exception, panic_flags; -#endif - - /* - * 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. - * This should only need setting if the EC completely lost power (for - * example, the battery was pulled). - */ - if (!(LM4_HIBERNATE_HIBCTL & LM4_HIBCTL_CLK32EN)) { - int i; - - /* Enable clock to hibernate module */ - wait_for_hibctl_wc(); - LM4_HIBERNATE_HIBCTL |= LM4_HIBCTL_CLK32EN; - - /* Wait for write-complete */ - for (i = 0; i < 1000000; i++) { - if (LM4_HIBERNATE_HIBRIS & 0x10) - break; - } - - /* Enable and reset RTC */ - wait_for_hibctl_wc(); - LM4_HIBERNATE_HIBCTL |= LM4_HIBCTL_RTCEN; - system_set_rtc(0); - - /* Clear all hibernate data entries */ - for (i = 0; i < LM4_HIBERNATE_HIBDATA_ENTRIES; i++) - hibdata_write(i, 0); - } - - /* - * Set wake reasons to RTC match and WAKE pin by default. - * Before going in to hibernate, these may change. - */ - hibctl = LM4_HIBERNATE_HIBCTL; - hibctl |= LM4_HIBCTL_RTCWEN; - hibctl |= LM4_HIBCTL_PINWEN; - wait_for_hibctl_wc(); - LM4_HIBERNATE_HIBCTL = hibctl; - - /* - * Initialize registers after reset to work around LM4 chip errata - * (still present in A3 chip stepping). - */ - wait_for_hibctl_wc(); - LM4_HIBERNATE_HIBRTCT = 0x7fff; - wait_for_hibctl_wc(); - LM4_HIBERNATE_HIBIM = 0; - - check_reset_cause(); - -#ifdef CONFIG_SOFTWARE_PANIC - /* Restore then clear saved panic reason */ - reason = hibdata_read(HIBDATA_INDEX_SAVED_PANIC_REASON); - info = hibdata_read(HIBDATA_INDEX_SAVED_PANIC_INFO); - exception = hibdata_read(HIBDATA_INDEX_SAVED_PANIC_EXCEPTION); - panic_flags = hibdata_read(HIBDATA_INDEX_SAVED_PANIC_FLAGS); - - if (reason || info || exception) { - panic_set_reason(reason, info, exception); - panic_get_data()->flags = panic_flags; - hibdata_write(HIBDATA_INDEX_SAVED_PANIC_REASON, 0); - hibdata_write(HIBDATA_INDEX_SAVED_PANIC_INFO, 0); - hibdata_write(HIBDATA_INDEX_SAVED_PANIC_EXCEPTION, 0); - hibdata_write(HIBDATA_INDEX_SAVED_PANIC_FLAGS, 0); - } -#endif - - /* Initialize bootcfg if needed */ - if (LM4_SYSTEM_BOOTCFG != CONFIG_BOOTCFG_VALUE) { - /* read-modify-write */ - LM4_FLASH_FMD = (LM4_SYSTEM_BOOTCFG_MASK & LM4_SYSTEM_BOOTCFG) - | (~LM4_SYSTEM_BOOTCFG_MASK & CONFIG_BOOTCFG_VALUE); - LM4_FLASH_FMA = 0x75100000; - LM4_FLASH_FMC = 0xa4420008; /* WRKEY | COMT */ - while (LM4_FLASH_FMC & 0x08) - ; - } - - /* Brown-outs should trigger a reset */ - LM4_SYSTEM_PBORCTL |= 0x02; -} - -void system_reset(int flags) -{ - uint32_t save_flags = 0; - - /* Disable interrupts to avoid task swaps during reboot */ - interrupt_disable(); - - /* Save current reset reasons if necessary */ - if (flags & SYSTEM_RESET_PRESERVE_FLAGS) - save_flags = system_get_reset_flags() | EC_RESET_FLAG_PRESERVED; - - if (flags & SYSTEM_RESET_LEAVE_AP_OFF) - save_flags |= EC_RESET_FLAG_AP_OFF; - - chip_save_reset_flags(save_flags); - - if (flags & SYSTEM_RESET_HARD) { -#ifdef CONFIG_SOFTWARE_PANIC - uint32_t reason, info; - uint8_t exception, panic_flags; - - panic_flags = panic_get_data()->flags; - - /* Panic data will be wiped by hard reset, so save it */ - panic_get_reason(&reason, &info, &exception); - hibdata_write(HIBDATA_INDEX_SAVED_PANIC_REASON, reason); - hibdata_write(HIBDATA_INDEX_SAVED_PANIC_INFO, info); - hibdata_write(HIBDATA_INDEX_SAVED_PANIC_EXCEPTION, exception); - hibdata_write(HIBDATA_INDEX_SAVED_PANIC_FLAGS, panic_flags); -#endif - - /* - * Bounce through hibernate to trigger a hard reboot. Do - * not wake on wake pin, since we need the full duration. - */ - hibernate(0, HIB_RESET_USEC, HIBDATA_WAKE_HARD_RESET); - } else - CPU_NVIC_APINT = 0x05fa0004; - - /* Spin and wait for reboot; should never return */ - while (1) - ; -} - -int system_set_scratchpad(uint32_t value) -{ - return hibdata_write(HIBDATA_INDEX_SCRATCHPAD, value); -} - -int system_get_scratchpad(uint32_t *value) -{ - *value = hibdata_read(HIBDATA_INDEX_SCRATCHPAD); - return EC_SUCCESS; -} - -const char *system_get_chip_vendor(void) -{ - return "ti"; -} - -static char to_hex(int x) -{ - if (x >= 0 && x <= 9) - return '0' + x; - return 'a' + x - 10; -} - -const char *system_get_chip_id_string(void) -{ - static char str[15] = "Unknown-"; - char *p = str + 8; - uint32_t did = LM4_SYSTEM_DID1 >> 16; - - if (*p) - return (const char *)str; - - *p = to_hex(did >> 12); - *(p + 1) = to_hex((did >> 8) & 0xf); - *(p + 2) = to_hex((did >> 4) & 0xf); - *(p + 3) = to_hex(did & 0xf); - *(p + 4) = '\0'; - - return (const char *)str; -} - -const char *system_get_raw_chip_name(void) -{ - switch ((LM4_SYSTEM_DID1 & 0xffff0000) >> 16) { - case 0x10de: - return "tm4e1g31h6zrb"; - case 0x10e2: - return "lm4fsxhh5bb"; - case 0x10e3: - return "lm4fs232h5bb"; - case 0x10e4: - return "lm4fs99h5bb"; - case 0x10e6: - return "lm4fs1ah5bb"; - case 0x10ea: - return "lm4fs1gh5bb"; - default: - return system_get_chip_id_string(); - } -} - -const char *system_get_chip_name(void) -{ - const char *postfix = "-tm"; /* test mode */ - static char str[20]; - const char *raw_chip_name = system_get_raw_chip_name(); - char *p = str; - - if (LM4_TEST_MODE_ENABLED) { - /* Debug mode is enabled. Postfix chip name. */ - while (*raw_chip_name) - *(p++) = *(raw_chip_name++); - while (*postfix) - *(p++) = *(postfix++); - *p = '\0'; - return (const char *)str; - } else { - return raw_chip_name; - } -} - -int system_get_bbram(enum system_bbram_idx idx, uint8_t *value) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int system_set_bbram(enum system_bbram_idx idx, uint8_t value) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -const char *system_get_chip_revision(void) -{ - static char rev[3]; - - /* Extract the major[15:8] and minor[7:0] revisions. */ - rev[0] = 'A' + ((LM4_SYSTEM_DID0 >> 8) & 0xff); - rev[1] = '0' + (LM4_SYSTEM_DID0 & 0xff); - rev[2] = 0; - - return rev; -} - -/*****************************************************************************/ -/* Console commands */ -void print_system_rtc(enum console_channel ch) -{ - uint32_t rtc; - uint32_t rtcss; - - rtc = system_get_rtc_sec_subsec(&rtcss); - cprintf(ch, "RTC: 0x%08x.%04x (%d.%06d s)\n", - rtc, rtcss, rtc, HIB_RTC_SUBSEC_TO_USEC(rtcss)); -} - -#ifdef CONFIG_CMD_RTC -static int command_system_rtc(int argc, char **argv) -{ - if (argc == 3 && !strcasecmp(argv[1], "set")) { - char *e; - uint32_t t = strtoi(argv[2], &e, 0); - if (*e) - return EC_ERROR_PARAM2; - - system_set_rtc(t); - } else if (argc > 1) { - return EC_ERROR_INVAL; - } - - print_system_rtc(CC_COMMAND); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(rtc, command_system_rtc, - "[set <seconds>]", - "Get/set real-time clock"); - -#ifdef CONFIG_CMD_RTC_ALARM -/** - * Test the RTC alarm by setting an interrupt on RTC match. - */ -static int command_rtc_alarm_test(int argc, char **argv) -{ - int s = 1, us = 0; - char *e; - - ccprintf("Setting RTC alarm\n"); - system_enable_hib_interrupt(); - - if (argc > 1) { - s = strtoi(argv[1], &e, 10); - if (*e) - return EC_ERROR_PARAM1; - - } - if (argc > 2) { - us = strtoi(argv[2], &e, 10); - if (*e) - return EC_ERROR_PARAM2; - - } - - system_set_rtc_alarm(s, us); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(rtc_alarm, command_rtc_alarm_test, - "[seconds [microseconds]]", - "Test alarm"); -#endif /* CONFIG_CMD_RTC_ALARM */ -#endif /* CONFIG_CMD_RTC */ - -/*****************************************************************************/ -/* Host commands */ - -#ifdef CONFIG_HOSTCMD_RTC -static enum ec_status system_rtc_get_value(struct host_cmd_handler_args *args) -{ - struct ec_response_rtc *r = args->response; - - r->time = system_get_rtc_sec_subsec(NULL); - args->response_size = sizeof(*r); - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_RTC_GET_VALUE, - system_rtc_get_value, - EC_VER_MASK(0)); - -static enum ec_status system_rtc_set_value(struct host_cmd_handler_args *args) -{ - const struct ec_params_rtc *p = args->params; - - system_set_rtc(p->time); - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_RTC_SET_VALUE, - system_rtc_set_value, - EC_VER_MASK(0)); -#endif /* CONFIG_HOSTCMD_RTC */ diff --git a/chip/lm4/uart.c b/chip/lm4/uart.c deleted file mode 100644 index 83136d0b46..0000000000 --- a/chip/lm4/uart.c +++ /dev/null @@ -1,352 +0,0 @@ -/* Copyright 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. - */ - -/* UART module for Chrome EC */ - -#include "clock.h" -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "lpc.h" -#include "registers.h" -#include "system.h" -#include "task.h" -#include "uart.h" -#include "util.h" - -#ifdef CONFIG_UART_HOST -#define IRQ_UART_HOST CONCAT2(LM4_IRQ_UART, CONFIG_UART_HOST) -#endif - -static int init_done; - -int uart_init_done(void) -{ - return init_done; -} - -void uart_tx_start(void) -{ - /* If interrupt is already enabled, nothing to do */ - if (LM4_UART_IM(0) & 0x20) - return; - - /* Do not allow deep sleep while transmit in progress */ - disable_sleep(SLEEP_MASK_UART); - - /* - * Re-enable the transmit interrupt, then forcibly trigger the - * interrupt. This works around a hardware problem with the - * UART where the FIFO only triggers the interrupt when its - * threshold is _crossed_, not just met. - */ - LM4_UART_IM(0) |= 0x20; - task_trigger_irq(LM4_IRQ_UART0); -} - -void uart_tx_stop(void) -{ - LM4_UART_IM(0) &= ~0x20; - - /* Re-allow deep sleep */ - enable_sleep(SLEEP_MASK_UART); -} - -void uart_tx_flush(void) -{ - /* Wait for transmit FIFO empty */ - while (!(LM4_UART_FR(0) & 0x80)) - ; -} - -int uart_tx_ready(void) -{ - return !(LM4_UART_FR(0) & 0x20); -} - -int uart_tx_in_progress(void) -{ - /* Transmit is in progress if the TX busy bit is set. */ - return LM4_UART_FR(0) & 0x08; -} - -int uart_rx_available(void) -{ - return !(LM4_UART_FR(0) & 0x10); -} - -void uart_write_char(char c) -{ - /* Wait for space in transmit FIFO. */ - while (!uart_tx_ready()) - ; - - LM4_UART_DR(0) = c; -} - -int uart_read_char(void) -{ - return LM4_UART_DR(0); -} - -static void uart_clear_rx_fifo(int channel) -{ - int scratch __attribute__ ((unused)); - while (!(LM4_UART_FR(channel) & 0x10)) - scratch = LM4_UART_DR(channel); -} - -/** - * Interrupt handler for UART0 - */ -static void uart_ec_interrupt(void) -{ - /* Clear transmit and receive interrupt status */ - LM4_UART_ICR(0) = 0x70; - - - /* Read input FIFO until empty, then fill output FIFO */ - uart_process_input(); - uart_process_output(); -} -DECLARE_IRQ(LM4_IRQ_UART0, uart_ec_interrupt, 1); - -#ifdef CONFIG_UART_HOST - -/** - * Interrupt handler for Host UART - */ -static void uart_host_interrupt(void) -{ - /* Clear transmit and receive interrupt status */ - LM4_UART_ICR(CONFIG_UART_HOST) = 0x70; - -#ifdef CONFIG_HOST_INTERFACE_LPC - /* - * If we have space in our FIFO and a character is pending in LPC, - * handle that character. - */ - if (!(LM4_UART_FR(CONFIG_UART_HOST) & 0x20) && lpc_comx_has_char()) { - /* Copy the next byte then disable transmit interrupt */ - LM4_UART_DR(CONFIG_UART_HOST) = lpc_comx_get_char(); - LM4_UART_IM(CONFIG_UART_HOST) &= ~0x20; - } - - /* - * Handle received character. There is no flow control on input; - * received characters are blindly forwarded to LPC. This is ok - * because LPC is much faster than UART, and we don't have flow control - * on the UART receive-side either. - */ - if (!(LM4_UART_FR(CONFIG_UART_HOST) & 0x10)) - lpc_comx_put_char(LM4_UART_DR(CONFIG_UART_HOST)); -#endif -} -/* Must be same prio as LPC interrupt handler so they don't preempt */ -DECLARE_IRQ(IRQ_UART_HOST, uart_host_interrupt, 2); - -#endif /* CONFIG_UART_HOST */ - -static void uart_config(int port) -{ - /* Disable the port */ - LM4_UART_CTL(port) = 0x0300; - /* Use the internal oscillator */ - LM4_UART_CC(port) = 0x1; - /* Set the baud rate divisor */ - LM4_UART_IBRD(port) = (INTERNAL_CLOCK / 16) / CONFIG_UART_BAUD_RATE; - LM4_UART_FBRD(port) = - (((INTERNAL_CLOCK / 16) % CONFIG_UART_BAUD_RATE) * 64 - + CONFIG_UART_BAUD_RATE / 2) / CONFIG_UART_BAUD_RATE; - /* - * 8-N-1, FIFO enabled. Must be done after setting - * the divisor for the new divisor to take effect. - */ - LM4_UART_LCRH(port) = 0x70; - /* - * Interrupt when RX fifo at minimum (>= 1/8 full), and TX fifo - * when <= 1/4 full - */ - LM4_UART_IFLS(port) = 0x01; - /* - * Unmask receive-FIFO, receive-timeout. We need - * receive-timeout because the minimum RX FIFO depth is 1/8 = 2 - * bytes; without the receive-timeout we'd never be notified - * about single received characters. - */ - LM4_UART_IM(port) = 0x50; - /* Enable the port */ - LM4_UART_CTL(port) |= 0x0001; -} - -void uart_init(void) -{ - uint32_t mask = 0; - - /* - * Enable UART0 in run, sleep, and deep sleep modes. Enable the Host - * UART in run and sleep modes. - */ - mask |= 1; - clock_enable_peripheral(CGC_OFFSET_UART, mask, CGC_MODE_ALL); - -#ifdef CONFIG_UART_HOST - mask |= BIT(CONFIG_UART_HOST); -#endif - - clock_enable_peripheral(CGC_OFFSET_UART, mask, - CGC_MODE_RUN | CGC_MODE_SLEEP); - - gpio_config_module(MODULE_UART, 1); - - /* Configure UARTs (identically) */ - uart_config(0); - -#ifdef CONFIG_UART_HOST - uart_config(CONFIG_UART_HOST); -#endif - - /* - * Enable interrupts for UART0 only. Host UART will have to wait - * until the LPC bus is initialized. - */ - uart_clear_rx_fifo(0); - task_enable_irq(LM4_IRQ_UART0); - - init_done = 1; -} - -#ifdef CONFIG_LOW_POWER_IDLE -void uart_enter_dsleep(void) -{ - const struct gpio_info g = gpio_list[GPIO_UART0_RX]; - - /* Disable the UART0 module interrupt. */ - task_disable_irq(LM4_IRQ_UART0); - - /* Disable UART0 peripheral in deep sleep. */ - clock_disable_peripheral(CGC_OFFSET_UART, 0x1, CGC_MODE_DSLEEP); - - /* - * Set the UART0 RX pin to be a generic GPIO with the flags defined - * in the board.c file. - */ - gpio_reset(GPIO_UART0_RX); - - /* Clear any pending GPIO interrupts on the UART0 RX pin. */ - LM4_GPIO_ICR(g.port) = g.mask; - - /* Enable GPIO interrupts on the UART0 RX pin. */ - gpio_enable_interrupt(GPIO_UART0_RX); -} - -void uart_exit_dsleep(void) -{ - const struct gpio_info g = gpio_list[GPIO_UART0_RX]; - - /* - * If the UART0 RX GPIO interrupt has not fired, then no edge has been - * detected. Disable the GPIO interrupt so that switching the pin over - * to a UART pin doesn't inadvertently cause a GPIO edge interrupt. - * Note: we can't disable this interrupt if it has already fired - * because then the IRQ will not get called. - */ - if (!(LM4_GPIO_MIS(g.port) & g.mask)) - gpio_disable_interrupt(GPIO_UART0_RX); - - /* Configure UART0 pins for use in UART peripheral. */ - gpio_config_module(MODULE_UART, 1); - - /* Clear pending interrupts on UART peripheral and enable interrupts. */ - uart_clear_rx_fifo(0); - task_enable_irq(LM4_IRQ_UART0); - - /* Enable UART0 peripheral in deep sleep */ - clock_enable_peripheral(CGC_OFFSET_UART, 0x1, CGC_MODE_DSLEEP); -} - -void uart_deepsleep_interrupt(enum gpio_signal signal) -{ - /* - * Activity seen on UART RX pin while UART was disabled for deep sleep. - * The console won't see that character because the UART is disabled, - * so we need to inform the clock module of UART activity ourselves. - */ - clock_refresh_console_in_use(); - - /* Disable interrupts on UART0 RX pin to avoid repeated interrupts. */ - gpio_disable_interrupt(GPIO_UART0_RX); -} -#endif /* CONFIG_LOW_POWER_IDLE */ - - -/*****************************************************************************/ -/* COMx functions */ - -#ifdef CONFIG_UART_HOST - -void uart_comx_enable(void) -{ - uart_clear_rx_fifo(CONFIG_UART_HOST); - task_enable_irq(IRQ_UART_HOST); -} - -int uart_comx_putc_ok(void) -{ - if (LM4_UART_FR(CONFIG_UART_HOST) & 0x20) { - /* - * FIFO is full, so enable transmit interrupt to let us know - * when it empties. - */ - LM4_UART_IM(CONFIG_UART_HOST) |= 0x20; - return 0; - } else { - return 1; - } -} - -void uart_comx_putc(int c) -{ - LM4_UART_DR(CONFIG_UART_HOST) = c; -} - -#endif /* CONFIG_UART_HOST */ - -/*****************************************************************************/ -/* Console commands */ - -#ifdef CONFIG_CMD_COMXTEST - -/** - * Write a character to COMx, waiting for space in the output buffer if - * necessary. - */ -static void uart_comx_putc_wait(int c) -{ - while (!uart_comx_putc_ok()) - ; - uart_comx_putc(c); -} - -static int command_comxtest(int argc, char **argv) -{ - /* Put characters to COMX port */ - const char *c = argc > 1 ? argv[1] : "testing comx output!"; - - ccprintf("Writing \"%s\\r\\n\" to COMx UART...\n", c); - - while (*c) - uart_comx_putc_wait(*c++); - - uart_comx_putc_wait('\r'); - uart_comx_putc_wait('\n'); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(comxtest, command_comxtest, - "[string]", - "Write test data to COMx uart"); - -#endif /* CONFIG_CMD_COMXTEST */ diff --git a/chip/lm4/watchdog.c b/chip/lm4/watchdog.c deleted file mode 100644 index 50f122bf02..0000000000 --- a/chip/lm4/watchdog.c +++ /dev/null @@ -1,120 +0,0 @@ -/* Copyright 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 "clock.h" -#include "common.h" -#include "registers.h" -#include "gpio.h" -#include "hooks.h" -#include "task.h" -#include "util.h" -#include "watchdog.h" - -/* - * We use watchdog 0 which is clocked on the system clock - * to avoid the penalty cycles on each write access - */ - -/* magic value to unlock the watchdog registers */ -#define LM4_WATCHDOG_MAGIC_WORD 0x1ACCE551 - -static uint32_t watchdog_period; /* Watchdog counter initial value */ - -void IRQ_HANDLER(LM4_IRQ_WATCHDOG)(void) __attribute__((naked)); -void IRQ_HANDLER(LM4_IRQ_WATCHDOG)(void) -{ - /* Naked call so we can extract raw LR and SP */ - asm volatile("mov r0, lr\n" - "mov r1, sp\n" - /* Must push registers in pairs to keep 64-bit aligned - * stack for ARM EABI. This also conveniently saves - * R0=LR so we can pass it to task_resched_if_needed. */ - "push {r0, lr}\n" - "bl watchdog_trace\n" - /* Do NOT reset the watchdog interrupt here; it will - * be done in watchdog_reload(), or reset will be - * triggered if we don't call that by the next watchdog - * period. Instead, de-activate the interrupt in the - * NVIC, so the watchdog trace will only be printed - * once. - */ - "mov r0, %[irq]\n" - "bl task_disable_irq\n" - "pop {r0, lr}\n" - "b task_resched_if_needed\n" - : : [irq] "i" (LM4_IRQ_WATCHDOG)); -} -const struct irq_priority __keep IRQ_PRIORITY(LM4_IRQ_WATCHDOG) - __attribute__((section(".rodata.irqprio"))) - = {LM4_IRQ_WATCHDOG, 0}; /* put the watchdog at the highest - priority */ - -void watchdog_reload(void) -{ - uint32_t status = LM4_WATCHDOG_RIS(0); - - /* Unlock watchdog registers */ - LM4_WATCHDOG_LOCK(0) = LM4_WATCHDOG_MAGIC_WORD; - - /* As we reboot only on the second timeout, if we have already reached - * the first timeout we need to reset the interrupt bit. */ - if (status) { - LM4_WATCHDOG_ICR(0) = status; - /* That doesn't seem to unpend the watchdog interrupt (even if - * we do writes to force the write to be committed), so - * explicitly unpend the interrupt before re-enabling it. */ - task_clear_pending_irq(LM4_IRQ_WATCHDOG); - task_enable_irq(LM4_IRQ_WATCHDOG); - } - - /* Reload the watchdog counter */ - LM4_WATCHDOG_LOAD(0) = watchdog_period; - - /* Re-lock watchdog registers */ - LM4_WATCHDOG_LOCK(0) = 0xdeaddead; -} -DECLARE_HOOK(HOOK_TICK, watchdog_reload, HOOK_PRIO_DEFAULT); - -static void watchdog_freq_changed(void) -{ - /* Set the timeout period */ - watchdog_period = CONFIG_WATCHDOG_PERIOD_MS * (clock_get_freq() / 1000); - - /* Reload the watchdog timer now */ - watchdog_reload(); -} -DECLARE_HOOK(HOOK_FREQ_CHANGE, watchdog_freq_changed, HOOK_PRIO_DEFAULT); - -int watchdog_init(void) -{ - /* 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(); - - /* Unlock watchdog registers */ - LM4_WATCHDOG_LOCK(0) = LM4_WATCHDOG_MAGIC_WORD; - - /* De-activate the watchdog when the JTAG stops the CPU */ - LM4_WATCHDOG_TEST(0) |= BIT(8); - - /* Reset after 2 time-out, activate the watchdog and lock the control - * register. */ - LM4_WATCHDOG_CTL(0) = 0x3; - - /* Reset watchdog interrupt bits */ - LM4_WATCHDOG_ICR(0) = LM4_WATCHDOG_RIS(0); - - /* Lock watchdog registers against unintended accesses */ - LM4_WATCHDOG_LOCK(0) = 0xdeaddead; - - /* Enable watchdog interrupt */ - task_enable_irq(LM4_IRQ_WATCHDOG); - - return EC_SUCCESS; -} |