mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-28 02:35:28 +00:00
Strago: Initial Version of Strago Board added.
Modules that are enabled are listed below: - Power Sequencing - Keyboard Scan and Protocol - LPC to support Keyboard - Power Button Task ec.spi.bin has to be generated manualy using pack_ec.py BUG=None BRANCH=None TEST=Tested on Stargo-Proto board Change-Id: Ic5d504c3d6e9c7c5f3482fb7e9e37800b6274824 Signed-off-by: Divya Jyothi <divya.jyothi@intel.com> Reviewed-on: https://chromium-review.googlesource.com/226303 Reviewed-by: Vic Yang <victoryang@chromium.org>
This commit is contained in:
committed by
chrome-internal-fetch
parent
41cde66516
commit
75ced73838
28
board/strago/board.c
Normal file
28
board/strago/board.c
Normal file
@@ -0,0 +1,28 @@
|
||||
/* Copyright (c) 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.
|
||||
*/
|
||||
/* Strago board-specific configuration */
|
||||
|
||||
#include "extpower.h"
|
||||
#include "gpio.h"
|
||||
#include "lid_switch.h"
|
||||
#include "power.h"
|
||||
#include "power_button.h"
|
||||
#include "registers.h"
|
||||
#include "util.h"
|
||||
|
||||
#define GPIO_KB_INPUT (GPIO_INPUT | GPIO_PULL_UP)
|
||||
#define GPIO_KB_OUTPUT (GPIO_ODR_HIGH)
|
||||
#define GPIO_KB_OUTPUT_COL2 (GPIO_OUT_LOW)
|
||||
|
||||
#include "gpio_list.h"
|
||||
|
||||
/* power signal list. Must match order of enum power_signal. */
|
||||
const struct power_signal_info power_signal_list[] = {
|
||||
{GPIO_ALL_SYS_PGOOD, 1, "ALL_SYS_PWRGD"},
|
||||
{GPIO_RSMRST_L_PGOOD, 1, "RSMRST_N_PWRGD"},
|
||||
{GPIO_PCH_SLP_S3_L, 1, "SLP_S3#_DEASSERTED"},
|
||||
{GPIO_PCH_SLP_S4_L, 1, "SLP_S4#_DEASSERTED"},
|
||||
};
|
||||
BUILD_ASSERT(ARRAY_SIZE(power_signal_list) == POWER_SIGNAL_COUNT);
|
||||
57
board/strago/board.h
Normal file
57
board/strago/board.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
/* Strago board configuration */
|
||||
|
||||
#ifndef __BOARD_H
|
||||
#define __BOARD_H
|
||||
|
||||
|
||||
/* Optional features */
|
||||
#define CONFIG_SYSTEM_UNLOCKED /* Allow dangerous commands */
|
||||
#define CONFIG_WATCHDOG_HELP
|
||||
#define CONFIG_CHIPSET_BRASWELL
|
||||
#define CONFIG_KEYBOARD_PROTOCOL_8042
|
||||
#define CONFIG_KEYBOARD_IRQ_GPIO GPIO_KBD_IRQ_L
|
||||
#define CONFIG_KEYBOARD_COL2_INVERTED
|
||||
#define CONFIG_POWER_BUTTON
|
||||
#define CONFIG_POWER_BUTTON_X86
|
||||
#define CONFIG_LID_SWITCH
|
||||
#define CONFIG_POWER_COMMON
|
||||
#define CONFIG_EXTPOWER_GPIO
|
||||
|
||||
/* Modules we want to exclude */
|
||||
#undef CONFIG_EEPROM
|
||||
#undef CONFIG_EOPTION
|
||||
#undef CONFIG_PSTORE
|
||||
#undef CONFIG_PECI
|
||||
#undef CONFIG_SWITCH
|
||||
#undef CONFIG_I2C
|
||||
#undef CONFIG_PWM
|
||||
#undef CONFIG_FANS
|
||||
#undef CONFIG_ADC
|
||||
#undef CONFIG_WAKE_PIN
|
||||
#undef CONFIG_SPI
|
||||
#undef CONFIG_SPI_PORT
|
||||
#undef CONFIG_SPI_CS_GPIO
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include "gpio_signal.h"
|
||||
|
||||
/* power signal definitions */
|
||||
enum power_signal {
|
||||
X86_ALL_SYS_PWRGD = 0,
|
||||
X86_RSMRST_L_PWRGD,
|
||||
X86_SLP_S3_DEASSERTED,
|
||||
X86_SLP_S4_DEASSERTED,
|
||||
|
||||
/* Number of X86 signals */
|
||||
POWER_SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#endif /* !__ASSEMBLER__ */
|
||||
|
||||
#endif /* __BOARD_H */
|
||||
12
board/strago/build.mk
Normal file
12
board/strago/build.mk
Normal file
@@ -0,0 +1,12 @@
|
||||
# -*- makefile -*-
|
||||
# Copyright (c) 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.
|
||||
#
|
||||
# Board specific files build
|
||||
#
|
||||
|
||||
# the IC is SMSC MEC1322 / external SPI is 4MB / external clock is crystal
|
||||
CHIP:=mec1322
|
||||
|
||||
board-y=board.o
|
||||
26
board/strago/ec.tasklist
Normal file
26
board/strago/ec.tasklist
Normal file
@@ -0,0 +1,26 @@
|
||||
/* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* List of enabled tasks in the priority order
|
||||
*
|
||||
* The first one has the lowest priority.
|
||||
*
|
||||
* For each task, use the macro TASK_ALWAYS(n, r, d, s) for base tasks and
|
||||
* TASK_NOTEST(n, r, d, s) for tasks that can be excluded in test binaries,
|
||||
* where :
|
||||
* 'n' in the name of the task
|
||||
* 'r' in the main routine of the task
|
||||
* 'd' in an opaque parameter passed to the routine at startup
|
||||
* 's' is the stack size in bytes; must be a multiple of 8
|
||||
*/
|
||||
#define CONFIG_TASK_LIST \
|
||||
TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \
|
||||
TASK_ALWAYS(HOSTCMD, host_command_task, NULL, TASK_STACK_SIZE) \
|
||||
TASK_ALWAYS(POWERBTN, power_button_task, NULL, TASK_STACK_SIZE) \
|
||||
TASK_NOTEST(KEYPROTO, keyboard_protocol_task, NULL, TASK_STACK_SIZE) \
|
||||
TASK_NOTEST(KEYSCAN, keyboard_scan_task, NULL, TASK_STACK_SIZE) \
|
||||
TASK_NOTEST(CHIPSET, chipset_task, NULL, TASK_STACK_SIZE) \
|
||||
TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE)
|
||||
53
board/strago/gpio.inc
Normal file
53
board/strago/gpio.inc
Normal file
@@ -0,0 +1,53 @@
|
||||
/* -*- mode:c -*-
|
||||
*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
GPIO(POWER_BUTTON_L, PORT(3), 5, GPIO_INT_BOTH_DSLEEP, power_button_interrupt) /* Power button */
|
||||
GPIO(LID_OPEN, PORT(2), 7, GPIO_INT_BOTH_DSLEEP, lid_interrupt) /* Lid switch */
|
||||
GPIO(PCH_PWRBTN_L, PORT(16), 0, GPIO_OUT_HIGH, NULL) /* Power button output to PCH */
|
||||
GPIO(STARTUP_LATCH_SET, PORT(4), 6, GPIO_OUT_HIGH, NULL) /* To enable power button detection */
|
||||
|
||||
GPIO(AC_PRESENT, PORT(3), 0, GPIO_INT_BOTH_DSLEEP, extpower_interrupt) /* BC_ACOK / EC_ACIN - to know if battery or AC connected */
|
||||
GPIO(RSMRST_L_PGOOD, PORT(6), 3, GPIO_INT_BOTH, power_signal_interrupt) /* RSMRST_N_PWRGD from power logic */
|
||||
GPIO(PCH_RSMRST_L, PORT(14), 3, GPIO_OUT_LOW, NULL) /* RSMRST_N to PCH */
|
||||
GPIO(PCH_SLP_S4_L, PORT(20), 0, GPIO_INT_BOTH_DSLEEP | GPIO_PULL_UP, power_signal_interrupt) /* SLP_S4# signal from PCH */
|
||||
GPIO(PCH_SLP_S3_L, PORT(20), 6, GPIO_INT_BOTH_DSLEEP | GPIO_PULL_UP, power_signal_interrupt) /* SLP_S3# signal from PCH */
|
||||
GPIO(ALL_SYS_PGOOD, PORT(13), 0, GPIO_INT_BOTH_DSLEEP, power_signal_interrupt) /* ALL_SYS_PWRGD from power logic */
|
||||
GPIO(PCH_SYS_PWROK, PORT(6), 5, GPIO_OUT_LOW, NULL) /* EC thinks everything is up and ready (DELAY_ALL_SYS_PWRGD) */
|
||||
|
||||
GPIO(USB3_PWR_EN, PORT(5), 7, GPIO_OUT_HIGH, NULL) /* Enable power for USB3 Port */
|
||||
GPIO(USB2_PWR_EN, PORT(3), 6, GPIO_OUT_HIGH, NULL) /* Enable power for USB2 Port */
|
||||
GPIO(USB_CTL1, PORT(10), 5, GPIO_OUT_HIGH, NULL) /* USB charging mode control */
|
||||
GPIO(USB_ILIM_SEL, PORT(1), 3, GPIO_OUT_HIGH, NULL) /* USB current control */
|
||||
|
||||
GPIO(KBD_IRQ_L, PORT(15), 2, GPIO_ODR_HIGH, NULL) /* Negative edge triggered irq. */
|
||||
|
||||
UNIMPLEMENTED(CPU_PROCHOT)
|
||||
UNIMPLEMENTED(PCH_RCIN_L)
|
||||
|
||||
GPIO(PCH_SMI_L, PORT(4), 4, GPIO_ODR_HIGH, NULL) /* SMI output */
|
||||
GPIO(PCH_WAKE_L, PORT(6), 6, GPIO_ODR_HIGH, NULL) /* PCH wake pin */
|
||||
GPIO(KBD_KSO2, PORT(10), 1, GPIO_KB_OUTPUT_COL2, NULL) /* Negative edge triggered irq. */
|
||||
|
||||
/*
|
||||
* Signals which aren't implemented on MEC1322 eval board but we'll
|
||||
* emulate anyway, to make it more convenient to debug other code.
|
||||
*/
|
||||
UNIMPLEMENTED(ENTERING_RW) /* EC entering RW code */
|
||||
|
||||
/* Alternate functions GPIO definition */
|
||||
ALTERNATE(PORT(16), 0x24, 1, MODULE_UART, 0) /* UART0 */
|
||||
ALTERNATE(PORT(0), 0x3f, 3, MODULE_KEYBOARD_SCAN, GPIO_KB_OUTPUT)
|
||||
ALTERNATE(PORT(10), 0xdd, 3, MODULE_KEYBOARD_SCAN, GPIO_KB_OUTPUT)
|
||||
ALTERNATE(PORT(3), 0x04, 3, MODULE_KEYBOARD_SCAN, GPIO_KB_INPUT)
|
||||
ALTERNATE(PORT(4), 0x0d, 3, MODULE_KEYBOARD_SCAN, GPIO_KB_INPUT)
|
||||
ALTERNATE(PORT(12), 0x60, 2, MODULE_KEYBOARD_SCAN, GPIO_KB_INPUT)
|
||||
ALTERNATE(PORT(14), 0x14, 3, MODULE_KEYBOARD_SCAN, GPIO_KB_INPUT)
|
||||
ALTERNATE(PORT(1), 0x10, 1, MODULE_LPC, 0) /* 14: CLKRUN# */
|
||||
ALTERNATE(PORT(11), 0x9e, 1, MODULE_LPC, 0) /* 111~114:LAD[0:3], 117:PCI_CLK */
|
||||
ALTERNATE(PORT(11), 0x40, 1, MODULE_LPC, GPIO_INT_BOTH) /* 116: LRESET# */
|
||||
ALTERNATE(PORT(12), 0x01, 1, MODULE_LPC, 0) /* 120: LFRAME# */
|
||||
ALTERNATE(PORT(5), 0x10, 1, MODULE_SPI, 0)
|
||||
@@ -31,12 +31,29 @@ void keyboard_raw_task_start(void)
|
||||
|
||||
test_mockable void keyboard_raw_drive_column(int out)
|
||||
{
|
||||
if (out == KEYBOARD_COLUMN_ALL)
|
||||
if (out == KEYBOARD_COLUMN_ALL) {
|
||||
MEC1322_KS_KSO_SEL = 1 << 5; /* KSEN=0, KSALL=1 */
|
||||
else if (out == KEYBOARD_COLUMN_NONE)
|
||||
#ifdef CONFIG_KEYBOARD_COL2_INVERTED
|
||||
gpio_set_level(GPIO_KBD_KSO2, 1);
|
||||
#endif
|
||||
} else if (out == KEYBOARD_COLUMN_NONE) {
|
||||
MEC1322_KS_KSO_SEL = 1 << 6; /* KSEN=1 */
|
||||
else
|
||||
MEC1322_KS_KSO_SEL = out + 4; /* KSO starts from KSO04 */
|
||||
#ifdef CONFIG_KEYBOARD_COL2_INVERTED
|
||||
gpio_set_level(GPIO_KBD_KSO2, 0);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef CONFIG_KEYBOARD_COL2_INVERTED
|
||||
if (out == 2) {
|
||||
MEC1322_KS_KSO_SEL = 1 << 6; /* KSEN=1 */
|
||||
gpio_set_level(GPIO_KBD_KSO2, 1);
|
||||
} else {
|
||||
MEC1322_KS_KSO_SEL = out;
|
||||
gpio_set_level(GPIO_KBD_KSO2, 0);
|
||||
}
|
||||
#else
|
||||
MEC1322_KS_KSO_SEL = out;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
test_mockable int keyboard_raw_read_rows(void)
|
||||
@@ -55,7 +72,7 @@ void keyboard_raw_enable_interrupt(int enable)
|
||||
}
|
||||
}
|
||||
|
||||
static void keyboard_raw_interrupt(void)
|
||||
void keyboard_raw_interrupt(void)
|
||||
{
|
||||
/* Clear interrupt status bits */
|
||||
MEC1322_KS_KSI_STATUS = 0xff;
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
#include "timer.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Console output macros */
|
||||
#define CPUTS(outstr) cputs(CC_LPC, outstr)
|
||||
#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args)
|
||||
|
||||
static uint8_t mem_mapped[0x200] __attribute__((section(".bss.big_align")));
|
||||
|
||||
static uint32_t host_events; /* Currently pending SCI/SMI events */
|
||||
@@ -32,6 +36,34 @@ static int init_done;
|
||||
static struct ec_lpc_host_args * const lpc_host_args =
|
||||
(struct ec_lpc_host_args *)mem_mapped;
|
||||
|
||||
|
||||
#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.
|
||||
*/
|
||||
gpio_set_level(CONFIG_KEYBOARD_IRQ_GPIO, 1);
|
||||
udelay(4);
|
||||
/* Generate a falling edge */
|
||||
gpio_set_level(CONFIG_KEYBOARD_IRQ_GPIO, 0);
|
||||
udelay(4);
|
||||
|
||||
/* Set signal high, now that we've generated the edge */
|
||||
gpio_set_level(CONFIG_KEYBOARD_IRQ_GPIO, 1);
|
||||
}
|
||||
#else
|
||||
static void keyboard_irq_assert(void)
|
||||
{
|
||||
/*
|
||||
* TODO(crosbug.com/p/24107): Implement SER_IRQ
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Generate SMI pulse to the host chipset via GPIO.
|
||||
*
|
||||
@@ -158,14 +190,14 @@ static void lpc_send_response_packet(struct host_packet *pkt)
|
||||
*/
|
||||
static void setup_lpc(void)
|
||||
{
|
||||
uintptr_t ptr = (uintptr_t)mem_mapped;
|
||||
|
||||
/* EMI module only takes alias memory address */
|
||||
if (ptr < 0x120000)
|
||||
ptr = ptr - 0x118000 + 0x20000000;
|
||||
|
||||
gpio_config_module(MODULE_LPC, 1);
|
||||
|
||||
/* Set up interrupt on LRESET# deassert */
|
||||
MEC1322_INT_SOURCE(19) |= 1 << 1;
|
||||
MEC1322_INT_ENABLE(19) |= 1 << 1;
|
||||
MEC1322_INT_BLK_EN |= 1 << 19;
|
||||
task_enable_irq(MEC1322_IRQ_GIRQ19);
|
||||
|
||||
/* Set up ACPI0 for 0x62/0x66 */
|
||||
MEC1322_LPC_ACPI_EC0_BAR = 0x00628034;
|
||||
MEC1322_INT_ENABLE(15) |= 1 << 6;
|
||||
@@ -181,18 +213,15 @@ static void setup_lpc(void)
|
||||
/* Set up 8042 interface at 0x60/0x64 */
|
||||
MEC1322_LPC_8042_BAR = 0x00608104;
|
||||
MEC1322_8042_ACT |= 1;
|
||||
MEC1322_INT_ENABLE(15) |= 1 << 14;
|
||||
MEC1322_INT_ENABLE(15) |= ((1 << 13) | (1 << 14));
|
||||
MEC1322_INT_BLK_EN |= 1 << 15;
|
||||
task_enable_irq(MEC1322_IRQ_8042EM_IBF);
|
||||
task_enable_irq(MEC1322_IRQ_8042EM_OBF);
|
||||
|
||||
/* TODO(crosbug.com/p/24107): Route KIRQ to SER_IRQ1 */
|
||||
|
||||
/* Set up EMI module for memory mapped region and port 80 */
|
||||
MEC1322_LPC_EMI_BAR = 0x0080800f;
|
||||
MEC1322_EMI_MBA0 = ptr;
|
||||
MEC1322_EMI_MRL0 = 0x200;
|
||||
MEC1322_EMI_MWL0 = 0x100;
|
||||
|
||||
MEC1322_INT_ENABLE(15) |= 1 << 2;
|
||||
MEC1322_INT_BLK_EN |= 1 << 15;
|
||||
task_enable_irq(MEC1322_IRQ_EMI);
|
||||
@@ -225,6 +254,27 @@ static void lpc_init(void)
|
||||
*/
|
||||
DECLARE_HOOK(HOOK_INIT, lpc_init, HOOK_PRIO_INIT_LPC);
|
||||
|
||||
void girq19_interrupt(void)
|
||||
{
|
||||
/* Check interrupt result for LRESET# trigger */
|
||||
if (MEC1322_INT_RESULT(19) & (1 << 1)) {
|
||||
/* Initialize LPC module when LRESET# is deasserted */
|
||||
if (!lpc_get_pltrst_asserted()) {
|
||||
setup_lpc();
|
||||
} else {
|
||||
/* Store port 80 reset event */
|
||||
port_80_write(PORT_80_EVENT_RESET);
|
||||
}
|
||||
|
||||
CPRINTS("LPC RESET# %sasserted",
|
||||
lpc_get_pltrst_asserted() ? "" : "de");
|
||||
|
||||
/* Clear interrupt source */
|
||||
MEC1322_INT_SOURCE(19) |= 1 << 1;
|
||||
}
|
||||
}
|
||||
DECLARE_IRQ(MEC1322_IRQ_GIRQ19, girq19_interrupt, 1);
|
||||
|
||||
void emi_interrupt(void)
|
||||
{
|
||||
port_80_write(MEC1322_EMI_H2E_MBX);
|
||||
@@ -313,6 +363,12 @@ void kb_ibf_interrupt(void)
|
||||
task_wake(TASK_ID_KEYPROTO);
|
||||
}
|
||||
DECLARE_IRQ(MEC1322_IRQ_8042EM_IBF, kb_ibf_interrupt, 1);
|
||||
|
||||
void kb_obf_interrupt(void)
|
||||
{
|
||||
task_wake(TASK_ID_KEYPROTO);
|
||||
}
|
||||
DECLARE_IRQ(MEC1322_IRQ_8042EM_OBF, kb_obf_interrupt, 1);
|
||||
#endif
|
||||
|
||||
int lpc_keyboard_has_char(void)
|
||||
@@ -328,21 +384,21 @@ int lpc_keyboard_input_pending(void)
|
||||
void lpc_keyboard_put_char(uint8_t chr, int send_irq)
|
||||
{
|
||||
MEC1322_8042_E2H = chr;
|
||||
/*
|
||||
* TODO(crosbug.com/p/24107): Implement SER_IRQ and handle
|
||||
* send_irq.
|
||||
*/
|
||||
if (send_irq)
|
||||
keyboard_irq_assert();
|
||||
}
|
||||
|
||||
void lpc_keyboard_clear_buffer(void)
|
||||
{
|
||||
volatile char dummy __attribute__((unused));
|
||||
|
||||
dummy = MEC1322_8042_OBF_CLR;
|
||||
}
|
||||
|
||||
void lpc_keyboard_resume_irq(void)
|
||||
{
|
||||
/* TODO(crosbug.com/p/24107): Implement SER_IRQ */
|
||||
if (lpc_keyboard_has_char())
|
||||
keyboard_irq_assert();
|
||||
}
|
||||
|
||||
void lpc_set_host_event_state(uint32_t mask)
|
||||
@@ -393,6 +449,11 @@ uint32_t lpc_get_host_event_mask(enum lpc_host_event_type type)
|
||||
return event_mask[type];
|
||||
}
|
||||
|
||||
int lpc_get_pltrst_asserted(void)
|
||||
{
|
||||
return (MEC1322_LPC_BUS_MONITOR & (1<<1)) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* On boards without a host, this command is used to set up LPC */
|
||||
static int lpc_command_init(int argc, char **argv)
|
||||
{
|
||||
|
||||
@@ -150,6 +150,7 @@ static inline uintptr_t gpio_port_base(int port_id)
|
||||
#define MEC1322_LPC_MEM_BAR_CFG REG32(MEC1322_LPC_CFG_BASE + 0xa4)
|
||||
|
||||
#define MEC1322_LPC_RT_BASE 0x400f3100
|
||||
#define MEC1322_LPC_BUS_MONITOR REG32(MEC1322_LPC_RT_BASE + 0x4)
|
||||
#define MEC1322_LPC_MEM_HOST_CFG REG32(MEC1322_LPC_RT_BASE + 0xfc)
|
||||
|
||||
|
||||
|
||||
@@ -118,11 +118,12 @@ static void set_pwrbtn_to_pch(int high)
|
||||
* If the battery is discharging and low enough we'd shut down the
|
||||
* system, don't press the power button.
|
||||
*/
|
||||
#ifdef CONFIG_CHARGER
|
||||
if (!high && charge_want_shutdown()) {
|
||||
CPRINTS("PB PCH pwrbtn ignored due to battery level");
|
||||
high = 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
CPRINTS("PB PCH pwrbtn=%s", high ? "HIGH" : "LOW");
|
||||
gpio_set_level(GPIO_PCH_PWRBTN_L, high);
|
||||
}
|
||||
|
||||
@@ -282,6 +282,7 @@
|
||||
#undef CONFIG_CHIPSET_IVYBRIDGE /* Intel Ivy Bridge (x86) */
|
||||
#undef CONFIG_CHIPSET_ROCKCHIP /* Rockchip rk32xx */
|
||||
#undef CONFIG_CHIPSET_TEGRA /* nVidia Tegra 5 */
|
||||
#undef CONFIG_CHIPSET_BRASWELL /* Intel Braswell (x86) */
|
||||
|
||||
/* Support chipset throttling */
|
||||
#undef CONFIG_CHIPSET_CAN_THROTTLE
|
||||
|
||||
327
power/braswell.c
Normal file
327
power/braswell.c
Normal file
@@ -0,0 +1,327 @@
|
||||
/* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
/* X86 braswell chipset power control module for Chrome EC */
|
||||
|
||||
#include "chipset.h"
|
||||
#include "common.h"
|
||||
#include "console.h"
|
||||
#include "ec_commands.h"
|
||||
#include "gpio.h"
|
||||
#include "hooks.h"
|
||||
#include "host_command.h"
|
||||
#include "lid_switch.h"
|
||||
#include "lpc.h"
|
||||
#include "power.h"
|
||||
#include "power_button.h"
|
||||
#include "system.h"
|
||||
#include "timer.h"
|
||||
#include "usb_charge.h"
|
||||
#include "util.h"
|
||||
#include "wireless.h"
|
||||
#include "registers.h"
|
||||
|
||||
/* Console output macros */
|
||||
#define CPUTS(outstr) cputs(CC_CHIPSET, outstr)
|
||||
#define CPRINTS(format, args...) cprints(CC_CHIPSET, format, ## args)
|
||||
|
||||
/* Input state flags */
|
||||
#define IN_RSMRST_L_PWRGD POWER_SIGNAL_MASK(X86_RSMRST_L_PWRGD)
|
||||
#define IN_ALL_SYS_PWRGD POWER_SIGNAL_MASK(X86_ALL_SYS_PWRGD)
|
||||
#define IN_SLP_S3_DEASSERTED POWER_SIGNAL_MASK(X86_SLP_S3_DEASSERTED)
|
||||
#define IN_SLP_S4_DEASSERTED POWER_SIGNAL_MASK(X86_SLP_S4_DEASSERTED)
|
||||
|
||||
/* All always-on supplies */
|
||||
#define IN_PGOOD_ALWAYS_ON (IN_RSMRST_L_PWRGD)
|
||||
/* All non-core power rails */
|
||||
#define IN_PGOOD_ALL_NONCORE (IN_ALL_SYS_PWRGD)
|
||||
/* All core power rails */
|
||||
#define IN_PGOOD_ALL_CORE (IN_ALL_SYS_PWRGD)
|
||||
/* Rails required for S5 */
|
||||
#define IN_PGOOD_S5 (IN_PGOOD_ALWAYS_ON)
|
||||
/* Rails required for S3 */
|
||||
#define IN_PGOOD_S3 (IN_PGOOD_ALWAYS_ON)
|
||||
/* Rails required for S0 */
|
||||
#define IN_PGOOD_S0 (IN_PGOOD_ALWAYS_ON | IN_PGOOD_ALL_NONCORE)
|
||||
|
||||
/* All PM_SLP signals from PCH deasserted */
|
||||
#define IN_ALL_PM_SLP_DEASSERTED (IN_SLP_S3_DEASSERTED | IN_SLP_S4_DEASSERTED)
|
||||
/* All inputs in the right state for S0 */
|
||||
#define IN_ALL_S0 (IN_PGOOD_ALWAYS_ON | IN_PGOOD_ALL_NONCORE | \
|
||||
IN_PGOOD_ALL_CORE | IN_ALL_PM_SLP_DEASSERTED)
|
||||
|
||||
static int throttle_cpu; /* Throttle CPU? */
|
||||
static int pause_in_s5 = 1; /* Pause in S5 when shutting down? */
|
||||
|
||||
void chipset_force_shutdown(void)
|
||||
{
|
||||
CPRINTS("%s()", __func__);
|
||||
|
||||
/*
|
||||
* Force power off. This condition will reset once the state machine
|
||||
* transitions to G3.
|
||||
*/
|
||||
gpio_set_level(GPIO_PCH_SYS_PWROK, 0);
|
||||
gpio_set_level(GPIO_PCH_RSMRST_L, 0);
|
||||
}
|
||||
|
||||
void chipset_reset(int cold_reset)
|
||||
{
|
||||
CPRINTS("%s(%d)", __func__, cold_reset);
|
||||
if (cold_reset) {
|
||||
/*
|
||||
* Drop and restore PWROK. This causes the PCH to reboot,
|
||||
* regardless of its after-G3 setting. This type of reboot
|
||||
* causes the PCH to assert PLTRST#, SLP_S3#, and SLP_S5#, so
|
||||
* we actually drop power to the rest of the system (hence, a
|
||||
* "cold" reboot).
|
||||
*/
|
||||
|
||||
/* Ignore if PWROK is already low */
|
||||
if (gpio_get_level(GPIO_PCH_SYS_PWROK) == 0)
|
||||
return;
|
||||
|
||||
/* PWROK must deassert for at least 3 RTC clocks = 91 us */
|
||||
gpio_set_level(GPIO_PCH_SYS_PWROK, 0);
|
||||
udelay(100);
|
||||
gpio_set_level(GPIO_PCH_SYS_PWROK, 1);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Send a reset pulse to the PCH. This just causes it to
|
||||
* assert INIT# to the CPU without dropping power or asserting
|
||||
* PLTRST# to reset the rest of the system. The PCH uses a 16
|
||||
* ms debounce time, so assert the signal for twice that.
|
||||
*/
|
||||
gpio_set_level(GPIO_PCH_RCIN_L, 0);
|
||||
usleep(32 * MSEC);
|
||||
gpio_set_level(GPIO_PCH_RCIN_L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void chipset_throttle_cpu(int throttle)
|
||||
{
|
||||
if (chipset_in_state(CHIPSET_STATE_ON))
|
||||
gpio_set_level(GPIO_CPU_PROCHOT, throttle);
|
||||
}
|
||||
|
||||
enum power_state power_chipset_init(void)
|
||||
{
|
||||
/*
|
||||
* If we're switching between images without rebooting, see if the x86
|
||||
* is already powered on; if so, leave it there instead of cycling
|
||||
* through G3.
|
||||
*/
|
||||
if (system_jumped_to_this_image()) {
|
||||
if ((power_get_signals() & IN_PGOOD_S0) == IN_PGOOD_S0) {
|
||||
/* Disable idle task deep sleep when in S0. */
|
||||
disable_sleep(SLEEP_MASK_AP_RUN);
|
||||
|
||||
CPRINTS("already in S0");
|
||||
return POWER_S0;
|
||||
} else {
|
||||
/* Force all signals to their G3 states */
|
||||
CPRINTS("forcing G3");
|
||||
gpio_set_level(GPIO_PCH_SYS_PWROK, 0);
|
||||
gpio_set_level(GPIO_PCH_RSMRST_L, 0);
|
||||
|
||||
/*wireless_set_state(WIRELESS_OFF);*/
|
||||
}
|
||||
}
|
||||
|
||||
return POWER_G3;
|
||||
}
|
||||
|
||||
enum power_state power_handle_state(enum power_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case POWER_G3:
|
||||
break;
|
||||
|
||||
case POWER_G3S5:
|
||||
if (power_wait_signals(IN_PGOOD_S5)) {
|
||||
chipset_force_shutdown();
|
||||
return POWER_G3;
|
||||
}
|
||||
|
||||
/* Deassert RSMRST# */
|
||||
gpio_set_level(GPIO_PCH_RSMRST_L, 1);
|
||||
return POWER_S5;
|
||||
|
||||
case POWER_S5:
|
||||
/* Check for SLP S4 */
|
||||
if (gpio_get_level(GPIO_PCH_SLP_S4_L) == 1)
|
||||
return POWER_S5S3; /* Power up to next state */
|
||||
break;
|
||||
|
||||
case POWER_S5S3:
|
||||
|
||||
/* Call hooks now that rails are up */
|
||||
hook_notify(HOOK_CHIPSET_STARTUP);
|
||||
|
||||
return POWER_S3;
|
||||
|
||||
|
||||
case POWER_S3:
|
||||
|
||||
/* Check for state transitions */
|
||||
if (!power_has_signals(IN_PGOOD_S3)) {
|
||||
/* Required rail went away */
|
||||
chipset_force_shutdown();
|
||||
return POWER_S3S5;
|
||||
} else if (gpio_get_level(GPIO_PCH_SLP_S3_L) == 1) {
|
||||
/* Power up to next state */
|
||||
return POWER_S3S0;
|
||||
} else if (gpio_get_level(GPIO_PCH_SLP_S4_L) == 0) {
|
||||
/* Power down to next state */
|
||||
return POWER_S3S5;
|
||||
}
|
||||
break;
|
||||
|
||||
case POWER_S3S0:
|
||||
/* Enable wireless */
|
||||
|
||||
/*wireless_set_state(WIRELESS_ON);*/
|
||||
|
||||
if (power_wait_signals(IN_PGOOD_S0)) {
|
||||
chipset_force_shutdown();
|
||||
|
||||
/*wireless_set_state(WIRELESS_OFF);*/
|
||||
return POWER_S3;
|
||||
}
|
||||
|
||||
/* Call hooks now that rails are up */
|
||||
hook_notify(HOOK_CHIPSET_RESUME);
|
||||
|
||||
/*
|
||||
* Disable idle task deep sleep. This means that the low
|
||||
* power idle task will not go into deep sleep while in S0.
|
||||
*/
|
||||
disable_sleep(SLEEP_MASK_AP_RUN);
|
||||
|
||||
/*
|
||||
* Wait 15 ms after all voltages good. 100 ms is only needed
|
||||
* for PCIe devices; mini-PCIe devices should need only 10 ms.
|
||||
*/
|
||||
msleep(15);
|
||||
|
||||
/*
|
||||
* Throttle CPU if necessary. This should only be asserted
|
||||
* when +VCCP is powered (it is by now).
|
||||
*/
|
||||
gpio_set_level(GPIO_CPU_PROCHOT, throttle_cpu);
|
||||
|
||||
/* Set SYS and CORE PWROK */
|
||||
gpio_set_level(GPIO_PCH_SYS_PWROK, 1);
|
||||
|
||||
/* Wait 50 ms for platform reset to deassert */
|
||||
{
|
||||
int i = 0;
|
||||
CPRINTS("power wait for PLTRST# to deassert");
|
||||
while (lpc_get_pltrst_asserted()) {
|
||||
usleep(MSEC);
|
||||
#ifndef STRAGO_PO
|
||||
i++;
|
||||
#endif
|
||||
if (i >= 50) {
|
||||
CPRINTS("power timeout on PLTRST#");
|
||||
chipset_force_shutdown();
|
||||
|
||||
/*wireless_set_state(WIRELESS_OFF);*/
|
||||
return POWER_S3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return POWER_S0;
|
||||
|
||||
|
||||
case POWER_S0:
|
||||
if (!power_has_signals(IN_PGOOD_S0)) {
|
||||
/* Required rail went away - Cold Reset? */
|
||||
chipset_force_shutdown();
|
||||
return POWER_S0S3;
|
||||
} else if (gpio_get_level(GPIO_PCH_SLP_S3_L) == 0) {
|
||||
/* Power down to next state */
|
||||
return POWER_S0S3;
|
||||
}
|
||||
|
||||
break;
|
||||
case POWER_S0S3:
|
||||
/* Call hooks before we remove power rails */
|
||||
hook_notify(HOOK_CHIPSET_SUSPEND);
|
||||
|
||||
/* Clear SYS and CORE PWROK */
|
||||
gpio_set_level(GPIO_PCH_SYS_PWROK, 0);
|
||||
|
||||
/* Wait 40ns */
|
||||
udelay(1);
|
||||
|
||||
/* Suspend wireless */
|
||||
|
||||
/*wireless_set_state(WIRELESS_SUSPEND);*/
|
||||
|
||||
/*
|
||||
* Enable idle task deep sleep. Allow the low power idle task
|
||||
* to go into deep sleep in S3 or lower.
|
||||
*/
|
||||
enable_sleep(SLEEP_MASK_AP_RUN);
|
||||
|
||||
/*
|
||||
* Deassert prochot since CPU is off and we're about to drop
|
||||
* +VCCP.
|
||||
*/
|
||||
gpio_set_level(GPIO_CPU_PROCHOT, 0);
|
||||
|
||||
return POWER_S3;
|
||||
|
||||
case POWER_S3S5:
|
||||
/* Call hooks before we remove power rails */
|
||||
hook_notify(HOOK_CHIPSET_SHUTDOWN);
|
||||
|
||||
/*wireless_set_state(WIRELESS_OFF);*/
|
||||
|
||||
/* Start shutting down */
|
||||
return pause_in_s5 ? POWER_S5 : POWER_S5G3;
|
||||
|
||||
case POWER_S5G3:
|
||||
/* Assert RSMRST# */
|
||||
gpio_set_level(GPIO_PCH_RSMRST_L, 0);
|
||||
return POWER_G3;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static int host_command_gsv(struct host_cmd_handler_args *args)
|
||||
{
|
||||
const struct ec_params_get_set_value *p = args->params;
|
||||
struct ec_response_get_set_value *r = args->response;
|
||||
|
||||
if (p->flags & EC_GSV_SET)
|
||||
pause_in_s5 = p->value;
|
||||
|
||||
r->value = pause_in_s5;
|
||||
|
||||
args->response_size = sizeof(*r);
|
||||
return EC_RES_SUCCESS;
|
||||
}
|
||||
DECLARE_HOST_COMMAND(EC_CMD_GSV_PAUSE_IN_S5,
|
||||
host_command_gsv,
|
||||
EC_VER_MASK(0));
|
||||
|
||||
static int console_command_gsv(int argc, char **argv)
|
||||
{
|
||||
if (argc > 1 && !parse_bool(argv[1], &pause_in_s5))
|
||||
return EC_ERROR_INVAL;
|
||||
|
||||
ccprintf("pause_in_s5 = %s\n", pause_in_s5 ? "on" : "off");
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
DECLARE_CONSOLE_COMMAND(pause_in_s5, console_command_gsv,
|
||||
"[on|off]",
|
||||
"Should the AP pause in S5 during shutdown?",
|
||||
NULL);
|
||||
@@ -12,4 +12,5 @@ power-$(CONFIG_CHIPSET_HASWELL)+=haswell.o
|
||||
power-$(CONFIG_CHIPSET_IVYBRIDGE)+=ivybridge.o
|
||||
power-$(CONFIG_CHIPSET_ROCKCHIP)+=rockchip.o
|
||||
power-$(CONFIG_CHIPSET_TEGRA)+=tegra.o
|
||||
power-$(CONFIG_CHIPSET_BRASWELL)+=braswell.o
|
||||
power-$(CONFIG_POWER_COMMON)+=common.o
|
||||
|
||||
Reference in New Issue
Block a user