Add PECI module and CPU temperature monitoring

Signed-off-by: Randall Spangler <rspangler@chromium.org>

BUG=chrome-os-partner:7493
TEST='powerbtn' to boot main processor, then 'temps' and 'pecitemp'

Change-Id: Id57526ebb37c8aecb05ecebccc2824f462b9de1a
This commit is contained in:
Randall Spangler
2012-02-10 14:09:42 -08:00
parent 186c81dcac
commit 6063ad473c
8 changed files with 184 additions and 16 deletions

View File

@@ -159,8 +159,10 @@ enum temp_sensor_id {
TEMP_SENSOR_I2C_DIE_NEAR_CHARGER,
/* EC internal temperature sensor */
TEMP_SENSOR_EC_INTERNAL,
/* CPU die temperature via PECI */
TEMP_SENSOR_CPU_PECI,
/* TODO: I2C temperature sensors. */
/* TODO: I2C remote temperature sensors. */
TEMP_SENSOR_COUNT
};

View File

@@ -9,6 +9,7 @@
#include "chip_temp_sensor.h"
#include "board.h"
#include "i2c.h"
#include "peci.h"
#define TEMP_CPU_REG_ADDR ((0x40 << 1) | I2C_FLAG_BIG_ENDIAN)
#define TEMP_PCH_REG_ADDR ((0x41 << 1) | I2C_FLAG_BIG_ENDIAN)
@@ -24,14 +25,16 @@
* temp_sensor_id.
*/
const struct temp_sensor_t temp_sensors[TEMP_SENSOR_COUNT] = {
{"CPU", TEMP_SENSOR_I2C_DIE_NEAR_CPU, TEMP_CPU_ADDR,
temp_sensor_tmp006_read_die_temp, temp_sensor_tmp006_print},
{"PCH", TEMP_SENSOR_I2C_DIE_NEAR_PCH, TEMP_PCH_ADDR,
temp_sensor_tmp006_read_die_temp, temp_sensor_tmp006_print},
{"DDR", TEMP_SENSOR_I2C_DIE_NEAR_DDR, TEMP_DDR_ADDR,
temp_sensor_tmp006_read_die_temp, temp_sensor_tmp006_print},
{"Charger", TEMP_SENSOR_I2C_DIE_NEAR_CHARGER, TEMP_CHARGER_ADDR,
temp_sensor_tmp006_read_die_temp, temp_sensor_tmp006_print},
{"I2C_CPU", TEMP_SENSOR_I2C_DIE_NEAR_CPU, TEMP_CPU_ADDR,
temp_sensor_tmp006_read_die_temp, temp_sensor_tmp006_print},
{"I2C_PCH", TEMP_SENSOR_I2C_DIE_NEAR_PCH, TEMP_PCH_ADDR,
temp_sensor_tmp006_read_die_temp, temp_sensor_tmp006_print},
{"I2C_DDR", TEMP_SENSOR_I2C_DIE_NEAR_DDR, TEMP_DDR_ADDR,
temp_sensor_tmp006_read_die_temp, temp_sensor_tmp006_print},
{"I2C_Charger", TEMP_SENSOR_I2C_DIE_NEAR_CHARGER, TEMP_CHARGER_ADDR,
temp_sensor_tmp006_read_die_temp, temp_sensor_tmp006_print},
{"ECInternal", TEMP_SENSOR_EC_INTERNAL, TEMP_SENSOR_NO_ADDR,
chip_temp_sensor_read, TEMP_SENSOR_NO_PRINT},
chip_temp_sensor_read, TEMP_SENSOR_NO_PRINT},
{"PECI", TEMP_SENSOR_CPU_PECI, TEMP_SENSOR_NO_ADDR,
peci_temp_sensor_read, TEMP_SENSOR_NO_PRINT},
};

View File

@@ -13,6 +13,7 @@ chip-y+=clock.o gpio.o system.o uart.o power_button.o
chip-y+=watchdog.o eeprom.o hwtimer.o
chip-$(CONFIG_FLASH)+=flash.o
chip-$(CONFIG_LPC)+=lpc.o
chip-$(CONFIG_PECI)+=peci.o
chip-$(CONFIG_PWM)+=pwm.o
chip-$(CONFIG_TEMP_SENSOR)+=chip_temp_sensor.o
chip-$(CONFIG_TASK_KEYSCAN)+=keyboard_scan.o

View File

@@ -37,6 +37,7 @@
#define CONFIG_PWM
#define CONFIG_TEMP_SENSOR
#define CONFIG_CHARGER
#define CONFIG_PECI
/* Compile for running from RAM instead of flash */
/* #define COMPILE_FOR_RAM */

106
chip/lm4/peci.c Normal file
View File

@@ -0,0 +1,106 @@
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* PECI interface for Chrome EC */
#include "board.h"
#include "console.h"
#include "gpio.h"
#include "peci.h"
#include "registers.h"
#include "uart.h"
#include "util.h"
/* Max junction temperature for processor in degrees C */
/* TODO: read TjMax from processor via PECI */
#define PECI_TJMAX 105
/* Initial PECI baud rate */
#define PECI_BAUD_RATE 150000
/* Polling interval for PECI, in ms */
#define PECI_POLL_INTERVAL_MS 200
/* Internal and external path delays, in ns */
#define PECI_TD_FET_NS 25 /* Guess; TODO: what is real delay */
#define PECI_TD_INT_NS 80
/* Configures the GPIOs for the PECI module. */
static void configure_gpios(void)
{
/* PJ6 alternate function 1 = PECI Tx */
gpio_set_alternate_function(LM4_GPIO_J, 0x40, 1);
/* PJ7 analog input = PECI Rx (comparator) */
LM4_GPIO_DEN(LM4_GPIO_J) &= ~0x80;
}
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_read(const struct temp_sensor_t* sensor)
{
if (sensor->id != TEMP_SENSOR_CPU_PECI)
return EC_ERROR_INVAL;
return peci_get_cpu_temp();
}
/*****************************************************************************/
/* Console commands */
static int command_peci_temp(int argc, char **argv)
{
int t = peci_get_cpu_temp();
if (t == -1) {
uart_puts("Error reading CPU temperature via PECI\n");
uart_printf("Error code = 0x%04x\n", LM4_PECI_M0D0 & 0xffff);
return EC_ERROR_UNKNOWN;
}
uart_printf("Current CPU temperature = %d K = %d C\n", t, t - 273);
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(pecitemp, command_peci_temp);
/*****************************************************************************/
/* Initialization */
int peci_init(void)
{
volatile uint32_t scratch __attribute__((unused));
int baud;
/* Enable the PECI module and delay a few clocks */
LM4_SYSTEM_RCGCPECI = 1;
scratch = LM4_SYSTEM_RCGCPECI;
/* Configure GPIOs */
configure_gpios();
/* Calculate baud setting from desired rate, compensating for internal
* and external delays. */
baud = CPU_CLOCK / (4 * PECI_BAUD_RATE) - 2;
baud -= (CPU_CLOCK / 1000000) * (PECI_TD_FET_NS + PECI_TD_INT_NS)
/ 1000;
/* Set baud rate and polling rate */
LM4_PECI_DIV = (baud << 16) |
(PECI_POLL_INTERVAL_MS * (CPU_CLOCK / 1000 / 4096));
/* Set up temperature monitoring to report in degrees K */
LM4_PECI_CTL = ((PECI_TJMAX + 273) << 22) | 0x2001;
return EC_SUCCESS;
}

View File

@@ -124,6 +124,29 @@ static inline int lm4_fan_addr(int ch, int offset)
#define LM4_EEPROM_EEINT LM4REG(0x400af040)
#define LM4_EEPROM_EEHIDE LM4REG(0x400af050)
#define LM4_PECI_CTL LM4REG(0x400b0000)
#define LM4_PECI_DIV LM4REG(0x400b0004)
#define LM4_PECI_CMP LM4REG(0x400b0008)
#define LM4_PECI_M0D0C LM4REG(0x400b0010)
#define LM4_PECI_M0D1C LM4REG(0x400b0014)
#define LM4_PECI_M1D0C LM4REG(0x400b0018)
#define LM4_PECI_M1D1C LM4REG(0x400b001c)
#define LM4_PECI_M0D0 LM4REG(0x400b0040)
#define LM4_PECI_M0D1 LM4REG(0x400b0044)
#define LM4_PECI_M1D0 LM4REG(0x400b0048)
#define LM4_PECI_M1D1 LM4REG(0x400b004c)
#define LM4_PECI_IM LM4REG(0x400b0080)
#define LM4_PECI_RIS LM4REG(0x400b0084)
#define LM4_PECI_MIS LM4REG(0x400b0088)
#define LM4_PECI_IC LM4REG(0x400b008c)
#define LM4_PECI_ACADDR LM4REG(0x400b0100)
#define LM4_PECI_ACARG LM4REG(0x400b0104)
#define LM4_PECI_ACRDWR0 LM4REG(0x400b0108)
#define LM4_PECI_ACRDWR1 LM4REG(0x400b010c)
#define LM4_PECI_ACCMD LM4REG(0x400b0110)
#define LM4_PECI_ACCODE LM4REG(0x400b0114)
#define LM4_HIBERNATE_HIBRTCC LM4REG(0x400fc000)
#define LM4_HIBERNATE_HIBRTCM0 LM4REG(0x400fc004)
#define LM4_HIBERNATE_HIBRTCLD LM4REG(0x400fc00c)
@@ -172,6 +195,7 @@ static inline int lm4_fan_addr(int ch, int offset)
#define LM4_SYSTEM_RCGCI2C LM4REG(0x400fe620)
#define LM4_SYSTEM_RCGCADC LM4REG(0x400fe638)
#define LM4_SYSTEM_RCGCLPC LM4REG(0x400fe648)
#define LM4_SYSTEM_RCGCPECI LM4REG(0x400fe650)
#define LM4_SYSTEM_RCGCFAN LM4REG(0x400fe654)
#define LM4_SYSTEM_RCGCEEPROM LM4REG(0x400fe658)
#define LM4_SYSTEM_RCGCWTIMER LM4REG(0x400fe65c)

View File

@@ -6,8 +6,10 @@
*/
#include "adc.h"
#include "config.h"
#include "charger.h"
#include "chip_temp_sensor.h"
#include "clock.h"
#include "config.h"
#include "console.h"
#include "eeprom.h"
#include "flash.h"
@@ -18,6 +20,7 @@
#include "keyboard.h"
#include "lpc.h"
#include "memory_commands.h"
#include "peci.h"
#include "port80.h"
#include "power_button.h"
#include "powerdemo.h"
@@ -25,16 +28,12 @@
#include "pwm_commands.h"
#include "system.h"
#include "task.h"
#ifdef CONFIG_TEMP_SENSOR
#include "temp_sensor.h"
#endif
#include "timer.h"
#include "uart.h"
#include "usb_charge.h"
#include "vboot.h"
#include "watchdog.h"
#include "usb_charge.h"
#include "chip_temp_sensor.h"
#include "charger.h"
int main(void)
{
@@ -87,6 +86,10 @@ int main(void)
charger_init();
#endif
#ifdef CONFIG_PECI
peci_init();
#endif
/* Print the reset cause */
uart_printf("\n\n--- Chrome EC initialized! ---\n");
uart_printf("(image: %s, version: %s, last reset: %s)\n",

28
include/peci.h Normal file
View File

@@ -0,0 +1,28 @@
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* PECI module for Chrome EC */
#ifndef __CROS_EC_PECI_H
#define __CROS_EC_PECI_H
#include "common.h"
#include "temp_sensor.h"
/* Initializes the module. */
int peci_init(void);
/* Returns the current CPU temperature in degrees K, or -1 if error.
*
* Note that the PECI interface is currently a little flaky; if you get an
* error, retry a bit later. */
int peci_get_cpu_temp(void);
/* Reads the CPU temperature sensor via PECI. This interface is for the
* temperature sensor module. Returns the temperature in degrees K, or -1 if
* error. */
int peci_temp_sensor_read(const struct temp_sensor_t *sensor);
#endif /* __CROS_EC_PECI_H */