ec/google: Add support for Realtek EC in ChromeOS EC

This commit adds the necessary infrastructure to support Realtek EC
controllers RTS5912/RTS5915 within the ChromeOS EC framework.

TEST=With this commit and 87702, flash to brox(rework realtek rts5915)
     Boot normally and got those message from ap console:

[DEBUG]  Google Chrome EC uptime: 698.137 seconds
[DEBUG]  Google Chrome AP resets since EC boot: 6
[DEBUG]  Google Chrome most recent AP reset causes:
[DEBUG]  	635.380: 8 reset: during EC initialization
[DEBUG]  	645.374: 32775 shutdown: entering G3
[DEBUG]  	680.284: 8 reset: during EC initialization
[DEBUG]  	684.586: 8 reset: during EC initialization
[DEBUG]  Google Chrome EC reset flags at last EC boot: soft
[DEBUG]  PNP: 0c09.0 init finished in 284 msecs

Change-Id: I44118c7b61a7efcee81acdd04be90b5022007a41
Signed-off-by: Jhan Bo Chao <jhan_bo_chao@realtek.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/87544
Reviewed-by: Keith Short <keithshort@chromium.org>
Reviewed-by: Karthik Ramasubramanian <kramasub@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Jhan Bo Chao 2025-05-15 21:49:55 +08:00 committed by Matt DeVillier
commit c776d2dbd6
7 changed files with 261 additions and 55 deletions

View file

@ -99,6 +99,13 @@ config EC_GOOGLE_CHROMEEC_MEC
help
Microchip EC variant for LPC register access.
config EC_GOOGLE_CHROMEEC_RTK
depends on EC_GOOGLE_CHROMEEC_LPC
def_bool n
select EC_GOOGLE_COMMON_RTK
help
Realtek EC variant for LPC register access.
config EC_GOOGLE_CHROMEEC_EC_HOST_CMD_DEBUG
depends on EC_GOOGLE_CHROMEEC_LPC && HAVE_MONOTONIC_TIMER
def_bool n
@ -211,6 +218,10 @@ config EC_GOOGLE_CHROMEEC_LPC_GENERIC_MEMORY_RANGE
Select this option to access LPC GMR (Generic Memory Range) Register to
implement MMIO based communication between EC and AP firmware.
config EC_GOOGLE_CHROMEEC_LPC_GENERIC_MEMORY_BASE
hex
default 0xfe0b0000
endif # EC_GOOGLE_CHROMEEC
source "src/ec/google/chromeec/*/Kconfig"

View file

@ -27,22 +27,32 @@ bootblock-$(CONFIG_EC_GOOGLE_CHROMEEC_SPI) += ec_spi.c
ifeq ($(CONFIG_EC_GOOGLE_CHROMEEC_SPI)$(CONFIG_EC_GOOGLE_CHROMEEC_I2C),y)
bootblock-y += crosec_proto.c
endif
bootblock-$(CONFIG_EC_GOOGLE_CHROMEEC_MEC) += mec.c
bootblock-$(CONFIG_EC_GOOGLE_CHROMEEC_RTK) += rtk.c
ramstage-y += ec.c crosec_proto.c vstore.c usbc_mux.c
ramstage-$(CONFIG_EC_GOOGLE_CHROMEEC_I2C) += ec_i2c.c
ramstage-$(CONFIG_EC_GOOGLE_CHROMEEC_LPC) += ec_lpc.c
ramstage-$(CONFIG_EC_GOOGLE_CHROMEEC_SPI) += ec_spi.c
ramstage-$(CONFIG_EC_GOOGLE_CHROMEEC_MEC) += mec.c
ramstage-$(CONFIG_EC_GOOGLE_CHROMEEC_RTK) += rtk.c
smm-y += ec.c crosec_proto.c smihandler.c vstore.c
smm-$(CONFIG_EC_GOOGLE_CHROMEEC_I2C) += ec_i2c.c
smm-$(CONFIG_EC_GOOGLE_CHROMEEC_LPC) += ec_lpc.c
smm-$(CONFIG_EC_GOOGLE_CHROMEEC_SPI) += ec_spi.c
smm-$(CONFIG_EC_GOOGLE_CHROMEEC_MEC) += mec.c
smm-$(CONFIG_EC_GOOGLE_CHROMEEC_RTK) += rtk.c
romstage-y += ec.c crosec_proto.c vstore.c
romstage-$(CONFIG_EC_GOOGLE_CHROMEEC_I2C) += ec_i2c.c
romstage-$(CONFIG_EC_GOOGLE_CHROMEEC_LPC) += ec_lpc.c
romstage-$(CONFIG_EC_GOOGLE_CHROMEEC_SPI) += ec_spi.c
romstage-$(CONFIG_EC_GOOGLE_CHROMEEC_MEC) += mec.c
romstage-$(CONFIG_EC_GOOGLE_CHROMEEC_RTK) += rtk.c
verstage-y += ec.c crosec_proto.c vstore.c
verstage-$(CONFIG_EC_GOOGLE_CHROMEEC_I2C) += ec_i2c.c
verstage-$(CONFIG_EC_GOOGLE_CHROMEEC_LPC) += ec_lpc.c
verstage-$(CONFIG_EC_GOOGLE_CHROMEEC_SPI) += ec_spi.c
verstage-$(CONFIG_EC_GOOGLE_CHROMEEC_MEC) += mec.c
verstage-$(CONFIG_EC_GOOGLE_CHROMEEC_RTK) += rtk.c
ramstage-$(CONFIG_HAVE_ACPI_TABLES) += ec_acpi.c
ramstage-$(CONFIG_VBOOT) += vboot_storage.c

View file

@ -116,14 +116,6 @@ int google_chromeec_cbi_get_ssfc(uint32_t *ssfc);
uint32_t google_chromeec_get_board_sku(void);
const char *google_chromeec_smbios_system_sku(void);
/* MEC uses 0x800/0x804 as register/index pair, thus an 8-byte resource. */
#define MEC_EMI_BASE 0x800
#define MEC_EMI_SIZE 8
/* For MEC, access ranges 0x800 thru 0x9ff using EMI interface instead of LPC */
#define MEC_EMI_RANGE_START EC_HOST_CMD_REGION0
#define MEC_EMI_RANGE_END (EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE)
int google_chromeec_set_usb_charge_mode(uint8_t port_id, enum usb_charge_mode mode);
int google_chromeec_set_usb_pd_role(uint8_t port, enum usb_pd_control_role role);
/*
@ -263,8 +255,7 @@ int google_chromeec_start_vboot_hash(enum ec_vboot_hash_type hash_type,
* @return 0 on success, -1 on error
*
*/
int google_chromeec_get_vboot_hash(uint32_t offset,
struct ec_response_vboot_hash *resp);
int google_chromeec_get_vboot_hash(uint32_t offset, struct ec_response_vboot_hash *resp);
/**
* Get offset and size of the specified EC flash region.
@ -495,4 +486,45 @@ const char *google_chromeec_acpi_name(const struct device *dev);
#endif /* HAVE_ACPI_TABLES */
/**
* Initialize the EC.
*/
void chipset_init(void);
/**
* Read bytes from the EMI.
*
* @param port IO port number
* @param length Length of the data to read
* @param dest Pointer to the destination buffer
* @param csum Pointer to the checksum buffer
*
* @return true indicates that the EC processes the read through the EMI interface
* and does not need to handle it through the IO port; otherwise, an IO read operation
* should be issued.
*/
bool chipset_emi_read_bytes(u16 port, size_t length, u8 *dest, u8 *csum);
/**
* Write bytes to the EMI.
*
* @param port IO port number
* @param length Length of the data to write
* @param msg Pointer to the message buffer
* @param csum Pointer to the checksum buffer
*
* @return true indicates that the EC processes the write through the EMI interface
* and does not need to handle it through the IO port; otherwise, an IO write operation
* should be issued.
*/
bool chipset_emi_write_bytes(u16 port, size_t length, u8 *msg, u8 *csum);
/**
* Get the IO port range. implement this function if the EC requires different IO ports.
*
* @param base Pointer to the base of the IO port range
* @param size Pointer to the size of the IO port range
*/
void chipset_ioport_range(uint16_t *base, size_t *size);
#endif /* _EC_GOOGLE_CHROMEEC_EC_H */

View file

@ -5,7 +5,6 @@
#include <console/console.h>
#include <delay.h>
#include <device/pnp.h>
#include <ec/google/common/mec.h>
#include <stdint.h>
#include <timer.h>
@ -13,6 +12,12 @@
#include "ec.h"
#include "ec_commands.h"
/* Return true if data read from EMI interface, false if no bytes transferred */
__weak bool chipset_emi_read_bytes(u16 port, size_t length, u8 *dest, u8 *csum)
{
return false;
}
/*
* Read bytes from a given LPC-mapped address.
*
@ -21,21 +26,14 @@
* @dest: Destination buffer
* @csum: Optional parameter, sums data read
*/
static void read_bytes(u16 port, unsigned int length, u8 *dest, u8 *csum)
static void read_bytes(u16 port, size_t length, u8 *dest, u8 *csum)
{
int i;
size_t i;
#if CONFIG(EC_GOOGLE_CHROMEEC_MEC)
/* Access desired range though EMI interface */
if (port >= MEC_EMI_RANGE_START && port <= MEC_EMI_RANGE_END) {
u8 ret = mec_io_bytes(MEC_IO_READ, MEC_EMI_BASE,
port - MEC_EMI_RANGE_START,
dest, length);
if (csum)
*csum += ret;
if (chipset_emi_read_bytes(port, length, dest, csum)) {
/* Access through EMI interface successful */
return;
}
#endif
for (i = 0; i < length; ++i) {
dest[i] = inb(port + i);
@ -61,6 +59,11 @@ static inline u8 read_byte_indexed_io(u8 offset)
}
#endif
__weak bool chipset_emi_write_bytes(u16 port, size_t length, u8 *msg, u8 *csum)
{
return false;
}
/*
* Write bytes to a given LPC-mapped address.
*
@ -69,21 +72,14 @@ static inline u8 read_byte_indexed_io(u8 offset)
* @msg: Write data buffer
* @csum: Optional parameter, sums data written
*/
static void write_bytes(u16 port, unsigned int length, u8 *msg, u8 *csum)
static void write_bytes(u16 port, size_t length, u8 *msg, u8 *csum)
{
int i;
size_t i;
#if CONFIG(EC_GOOGLE_CHROMEEC_MEC)
/* Access desired range though EMI interface */
if (port >= MEC_EMI_RANGE_START && port <= MEC_EMI_RANGE_END) {
u8 ret = mec_io_bytes(MEC_IO_WRITE, MEC_EMI_BASE,
port - MEC_EMI_RANGE_START,
msg, length);
if (csum)
*csum += ret;
if (chipset_emi_write_bytes(port, length, msg, csum)) {
/* Access through EMI interface successful */
return;
}
#endif
for (i = 0; i < length; ++i) {
outb(msg[i], port + i);
@ -127,6 +123,11 @@ static int google_chromeec_wait_ready(u16 port)
EC_LPC_CMDR_BUSY, 0);
}
static int google_chromeec_data_ready(u16 port)
{
return google_chromeec_status_check(port, EC_LPC_CMDR_DATA, EC_LPC_CMDR_DATA);
}
#if CONFIG(EC_GOOGLE_CHROMEEC_ACPI_MEMMAP)
/* Read memmap data through ACPI port 66/62 */
static int read_memmap(u8 *data, u8 offset)
@ -152,6 +153,13 @@ static int read_memmap(u8 *data, u8 offset)
return -1;
}
/* ap should wait b0 (OBF) */
if (CONFIG(EC_GOOGLE_CHROMEEC_RTK) &&
google_chromeec_data_ready(EC_LPC_ADDR_ACPI_CMD)) {
printk(BIOS_ERR, "Timeout waiting for EC DATA!\n");
return -1;
}
*data = read_byte(EC_LPC_ADDR_ACPI_DATA);
return 0;
}
@ -252,6 +260,14 @@ static int google_chromeec_command_v3(struct chromeec_command *cec_command)
return -1;
}
/* RTS5915: acpi port should wait status reg bit 0 (OBF),
and then take data from data register */
if (CONFIG(EC_GOOGLE_CHROMEEC_RTK) &&
google_chromeec_data_ready(EC_LPC_ADDR_HOST_CMD)) {
printk(BIOS_ERR, "Timeout waiting for EC DATA!\n");
return -1;
}
/* Check result */
cec_command->cmd_code = read_byte(EC_LPC_ADDR_HOST_DATA);
if (cec_command->cmd_code) {
@ -381,24 +397,18 @@ uint8_t google_chromeec_get_switches(void)
#endif
}
void __weak chipset_ioport_range(uint16_t *base, size_t *size)
{
*base = EC_HOST_CMD_REGION0;
*size = 2 * EC_HOST_CMD_REGION_SIZE;
/* Make sure MEMMAP region follows host cmd region. */
assert(*base + *size == EC_LPC_ADDR_MEMMAP);
*size += EC_MEMMAP_SIZE;
}
void google_chromeec_ioport_range(uint16_t *out_base, size_t *out_size)
{
uint16_t base;
size_t size;
if (CONFIG(EC_GOOGLE_CHROMEEC_MEC)) {
base = MEC_EMI_BASE;
size = MEC_EMI_SIZE;
} else {
base = EC_HOST_CMD_REGION0;
size = 2 * EC_HOST_CMD_REGION_SIZE;
/* Make sure MEMMAP region follows host cmd region. */
assert(base + size == EC_LPC_ADDR_MEMMAP);
size += EC_MEMMAP_SIZE;
}
*out_base = base;
*out_size = size;
chipset_ioport_range(out_base, out_size);
}
int google_chromeec_command(struct chromeec_command *cec_command)
@ -436,11 +446,14 @@ int google_chromeec_command(struct chromeec_command *cec_command)
return result;
}
void __weak chipset_init(void) {}
static void lpc_ec_init(struct device *dev)
{
if (!dev->enabled)
return;
chipset_init();
google_chromeec_init();
}
@ -494,12 +507,6 @@ struct chip_operations ec_google_chromeec_ops = {
.enable_dev = enable_dev,
};
static int google_chromeec_data_ready(u16 port)
{
return google_chromeec_status_check(port, EC_LPC_CMDR_DATA,
EC_LPC_CMDR_DATA);
}
enum host_event_code google_chromeec_get_event(void)
{
if (google_chromeec_wait_ready(EC_LPC_ADDR_ACPI_CMD)) {

View file

@ -0,0 +1,47 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <arch/io.h>
#include <ec/google/common/mec.h>
#include <stdint.h>
#include "ec.h"
/* MEC uses 0x800/0x804 as register/index pair, thus an 8-byte resource. */
#define MEC_EMI_BASE 0x800
#define MEC_EMI_SIZE 8
/* For MEC, access ranges 0x800 thru 0x9ff using EMI interface instead of LPC */
#define MEC_EMI_RANGE_START EC_HOST_CMD_REGION0
#define MEC_EMI_RANGE_END (EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE)
bool chipset_emi_read_bytes(u16 port, size_t length, u8 *dest, u8 *csum)
{
/* Access desired range though EMI interface */
if (port >= MEC_EMI_RANGE_START && port <= MEC_EMI_RANGE_END) {
u8 ret = mec_io_bytes(MEC_IO_READ, MEC_EMI_BASE, port - MEC_EMI_RANGE_START,
dest, length);
if (csum)
*csum += ret;
return true;
}
return false;
}
bool chipset_emi_write_bytes(u16 port, size_t length, u8 *msg, u8 *csum)
{
/* Access desired range though EMI interface */
if (port >= MEC_EMI_RANGE_START && port <= MEC_EMI_RANGE_END) {
u8 ret = mec_io_bytes(MEC_IO_WRITE, MEC_EMI_BASE, port - MEC_EMI_RANGE_START,
msg, length);
if (csum)
*csum += ret;
return true;
}
return false;
}
void chipset_ioport_range(uint16_t *base, size_t *size)
{
*base = MEC_EMI_BASE;
*size = MEC_EMI_SIZE;
}

View file

@ -0,0 +1,94 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <arch/io.h>
#include <stdint.h>
#include "ec.h"
/* For RTK, access ranges 0x800 thru 0x9ff using EMI interface instead of LPC */
#define EMI_RANGE_START EC_HOST_CMD_REGION0
#define EMI_RANGE_END (EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE)
#define HOSTCMD_PARAM_MEM_BASE CONFIG_EC_GOOGLE_CHROMEEC_LPC_GENERIC_MEMORY_BASE
#define ACPI_MEM_BASE (HOSTCMD_PARAM_MEM_BASE + 0x100)
#define SIO_CONFIG_PORT 0x2e
#define SIO_DATA_PORT 0x2f
#define SIO_LDN 0x07
#define EMI0_LDN 0x06
#define EMI1_LDN 0x07 /* EMI1 LDN */
#define EMI_ADDR3 0xf0 /* The EMI base address 31-24*/
#define EMI_ADDR2 0xf1 /* The EMI base address 23-16*/
#define EMI_ADDR1 0xf2 /* The EMI base address 15-8*/
#define EMI_CTRL 0x30
bool chipset_emi_read_bytes(u16 port, size_t length, u8 *dest, u8 *csum)
{
size_t i;
printk(BIOS_DEBUG, "RTS5915: read port 0x%x, size %ld\n", port, length);
if (port >= EMI_RANGE_START && port <= EMI_RANGE_END) {
uint8_t *p = (uint8_t *)(HOSTCMD_PARAM_MEM_BASE + (port - EMI_RANGE_START));
for (i = 0; i < length; ++i) {
dest[i] = p[i];
if (csum)
*csum += dest[i];
}
return true;
}
return false;
}
bool chipset_emi_write_bytes(u16 port, size_t length, u8 *msg, u8 *csum)
{
size_t i;
printk(BIOS_DEBUG, "RTS5915: write port 0x%x, size %ld\n", port, length);
if (port >= EMI_RANGE_START && port <= EMI_RANGE_END) {
uint8_t *p = (uint8_t *)(HOSTCMD_PARAM_MEM_BASE + (port - EMI_RANGE_START));
for (i = 0; i < length; ++i) {
p[i] = msg[i];
if (csum)
*csum += msg[i];
}
return true;
}
return false;
}
static inline void sio_write_config(uint8_t reg, uint8_t value)
{
outb(reg, SIO_CONFIG_PORT);
outb(value, SIO_DATA_PORT);
}
void chipset_init(void)
{
/*
* Due the hardware design, the RTS5915 EMI should be initiated by host sio command,
* The EMI range is 256 bytes, chromeec needs two region for host command and ACPI
* shared memory.
*/
printk(BIOS_INFO, "RTS5915 EMI: start init ...\n");
/* Configure the EMI0 to 0xfe0b0000 for host command parameters */
sio_write_config(SIO_LDN, EMI0_LDN);
sio_write_config(EMI_ADDR3, HOSTCMD_PARAM_MEM_BASE >> 24 & 0xff);
sio_write_config(EMI_ADDR2, HOSTCMD_PARAM_MEM_BASE >> 16 & 0xff);
sio_write_config(EMI_ADDR1, HOSTCMD_PARAM_MEM_BASE >> 8 & 0xff);
sio_write_config(EMI_CTRL, 0x01); /* Enable EMI */
/* Configure the EMI1 to 0xfe0b0100 for ACPI shared memory */
sio_write_config(SIO_LDN, EMI1_LDN);
sio_write_config(EMI_ADDR3, ACPI_MEM_BASE >> 24 & 0xff);
sio_write_config(EMI_ADDR2, ACPI_MEM_BASE >> 16 & 0xff);
sio_write_config(EMI_ADDR1, ACPI_MEM_BASE >> 8 & 0xff);
sio_write_config(EMI_CTRL, 0x01); /* Enable EMI */
printk(BIOS_INFO, "RTS5915 EMI: done\n");
}

View file

@ -4,3 +4,8 @@ config EC_GOOGLE_COMMON_MEC
bool
help
Google common EC functions for Microchip EMI region.
config EC_GOOGLE_COMMON_RTK
bool
help
Google common EC functions for Realtek EMI region.