diff --git a/src/ec/google/chromeec/Kconfig b/src/ec/google/chromeec/Kconfig index bcd2b13351..8e037f2496 100644 --- a/src/ec/google/chromeec/Kconfig +++ b/src/ec/google/chromeec/Kconfig @@ -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" diff --git a/src/ec/google/chromeec/Makefile.mk b/src/ec/google/chromeec/Makefile.mk index 10b6203e5d..659daf23a0 100644 --- a/src/ec/google/chromeec/Makefile.mk +++ b/src/ec/google/chromeec/Makefile.mk @@ -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 diff --git a/src/ec/google/chromeec/ec.h b/src/ec/google/chromeec/ec.h index b11b7a834a..957adb4089 100644 --- a/src/ec/google/chromeec/ec.h +++ b/src/ec/google/chromeec/ec.h @@ -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 */ diff --git a/src/ec/google/chromeec/ec_lpc.c b/src/ec/google/chromeec/ec_lpc.c index b32d25c6a8..19139ccc07 100644 --- a/src/ec/google/chromeec/ec_lpc.c +++ b/src/ec/google/chromeec/ec_lpc.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -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)) { diff --git a/src/ec/google/chromeec/mec.c b/src/ec/google/chromeec/mec.c new file mode 100644 index 0000000000..1ad7ba182d --- /dev/null +++ b/src/ec/google/chromeec/mec.c @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include + +#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; +} diff --git a/src/ec/google/chromeec/rtk.c b/src/ec/google/chromeec/rtk.c new file mode 100644 index 0000000000..6779d422f2 --- /dev/null +++ b/src/ec/google/chromeec/rtk.c @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include + +#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"); +} diff --git a/src/ec/google/common/Kconfig b/src/ec/google/common/Kconfig index 2005ddbfb9..324c4d9da8 100644 --- a/src/ec/google/common/Kconfig +++ b/src/ec/google/common/Kconfig @@ -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.