diff --git a/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts b/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts index 42716adfb2a..739ac703a43 100644 --- a/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts +++ b/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts @@ -15,6 +15,7 @@ aliases { i2c-0 = &i2c0; + peci-0 = &peci0; }; chosen { diff --git a/drivers/peci/CMakeLists.txt b/drivers/peci/CMakeLists.txt index e55c91ce959..1f27e9f7cd8 100644 --- a/drivers/peci/CMakeLists.txt +++ b/drivers/peci/CMakeLists.txt @@ -3,4 +3,5 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_PECI_XEC peci_mchp_xec.c) +zephyr_library_sources_ifdef(CONFIG_PECI_ITE_IT8XXX2 peci_ite_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE peci_handlers.c) diff --git a/drivers/peci/Kconfig b/drivers/peci/Kconfig index ebaedfaa217..e69e1cfc3ee 100644 --- a/drivers/peci/Kconfig +++ b/drivers/peci/Kconfig @@ -11,6 +11,7 @@ menuconfig PECI if PECI source "drivers/peci/Kconfig.xec" +source "drivers/peci/Kconfig.it8xxx2" module = PECI module-str = peci diff --git a/drivers/peci/Kconfig.it8xxx2 b/drivers/peci/Kconfig.it8xxx2 new file mode 100644 index 00000000000..ec92a08b7ec --- /dev/null +++ b/drivers/peci/Kconfig.it8xxx2 @@ -0,0 +1,10 @@ +# ITE IT8XXX2 PECI configuration options + +# Copyright (c) 2022 ITE Tech. Inc. +# SPDX-License-Identifier: Apache-2.0 + +config PECI_ITE_IT8XXX2 + bool "ITE IT8XXX2 PECI driver" + depends on SOC_IT8XXX2 + help + Enable the ITE IT8XXX2 PECI IO driver. diff --git a/drivers/peci/peci_ite_it8xxx2.c b/drivers/peci/peci_ite_it8xxx2.c new file mode 100644 index 00000000000..97743a39b82 --- /dev/null +++ b/drivers/peci/peci_ite_it8xxx2.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2022 ITE Corporation. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ite_peci_it8xxx2 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(peci_ite_it8xxx2, CONFIG_PECI_LOG_LEVEL); + +BUILD_ASSERT(IS_ENABLED(CONFIG_PECI_INTERRUPT_DRIVEN), + "Please enable the option CONFIG_PECI_INTERRUPT_DRIVEN"); + +/* + * This driver is single-instance. If the devicetree contains multiple + * instances, this will fail and the driver needs to be revisited. + */ +BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) <= 1, + "Unsupported PECI Instance"); + +/* The following constants decribes the bitrate of it8xxx2 PECI, + * for the frequency are 2000KHz, 1000KHz, and 1600KHz. (Unit: KHz) + */ +#define PECI_IT8XXX2_BITRATE_2MHZ 2000 +#define PECI_IT8XXX2_BITRATE_1MHZ 1000 +#define PECI_IT8XXX2_BITRATE_1P6MHZ 1600 + +/* The following masks are designed for the PECI bitrate settings, + * for the bits[7:3] are not related to this features. + */ +#define PECI_IT8XXX2_BITRATE_BITS_MASK 0x07 +#define PECI_IT8XXX2_BITRATE_2MHZ_BITS 0x00 +#define PECI_IT8XXX2_BITRATE_1MHZ_BITS 0x01 +#define PECI_IT8XXX2_BITRATE_1P6MHZ_BITS 0x04 + +/* The Transaction Timeout */ +#define PECI_TIMEOUT_MS 30 + +/* PECI interface 0 */ +#define PECI0 0 + +/* HOSTAR (F02C00h) */ +#define HOBY BIT(0) +#define FINISH BIT(1) +#define RD_FCS_ERR BIT(2) +#define WR_FCS_ERR BIT(3) +#define EXTERR BIT(5) +#define BUS_ER BIT(6) +#define TEMPERR BIT(7) +#define HOSTAR_RST_ANYBIT \ + (TEMPERR|BUS_ER|EXTERR|WR_FCS_ERR|RD_FCS_ERR|FINISH) + +/* HOCTLR (F02C01h) */ +#define START BIT(0) +#define AWFCS_EN BIT(1) +#define CONTROL BIT(2) +#define PECIHEN BIT(3) +#define FCSERR_ABT BIT(4) +#define FIFOCLR BIT(5) + +/* + * TODO: The Voltage Configuration + * Related DTSi and registers settings should be fulfilled + * in the future. + */ +/* PADCTLR (F02C0Eh) */ +#define PECI_DVIE 0x04 + +enum peci_vtts { + HOVTTS0P85V = 0x00, + HOVTTS0P90V = 0x01, + HOVTTS0P95V = 0x02, + HOVTTS1P00V = 0x03, + HOVTTS1P05V = 0x08, + HOVTTS1P10V = 0x09, + HOVTTS1P15V = 0x0A, + HOVTTS1P20V = 0x0B, + HOVTTS1P25V = 0x10, +}; + +/* The following definitions are inclusive of the config/data + * and related properties of the PECI device. + */ +struct peci_alts_cfg { + const struct device *pinctrls; + uint8_t pin; + uint8_t alt_fun; +}; + +struct peci_it8xxx2_config { + uintptr_t base_addr; + uint8_t irq_no; + const struct peci_alts_cfg *alts_list; +}; + +struct peci_it8xxx2_data { + struct peci_msg *msgs; + struct k_sem device_sync_sem; + uint32_t bitrate; +}; + +static const struct peci_alts_cfg + peci_alt_inst[DT_INST_NUM_PINCTRLS_BY_IDX(0, 0)] = + IT8XXX2_DT_ALT_ITEMS_LIST(0); + +static const struct peci_it8xxx2_config peci_it8xxx2_config0 = { + .base_addr = DT_INST_REG_ADDR(0), + .irq_no = DT_INST_IRQN(0), + .alts_list = peci_alt_inst, +}; + +static struct peci_it8xxx2_data peci_it8xxx2_data0; + +/* ITE IT8XXX2 PECI Functions */ + +static void peci_it8xxx2_init_vtts(struct peci_it8xxx2_regs *reg_base, + enum peci_vtts vol_opt) +{ + reg_base->PADCTLR = (reg_base->PADCTLR & PECI_DVIE) | vol_opt; +} + +static void peci_it8xxx2_rst_status(struct peci_it8xxx2_regs *reg_base) +{ + reg_base->HOSTAR = HOSTAR_RST_ANYBIT; +} + +static int peci_it8xxx2_check_host_busy(struct peci_it8xxx2_regs *reg_base) +{ + return (reg_base->HOSTAR & HOBY) ? (-EBUSY) : 0; +} + +static int peci_it8xxx2_check_host_finish(const struct device *dev) +{ + struct peci_it8xxx2_data *data = dev->data; + const struct peci_it8xxx2_config *config = dev->config; + struct peci_it8xxx2_regs *const peci_regs = + (struct peci_it8xxx2_regs *)config->base_addr; + + int ret = k_sem_take(&data->device_sync_sem, K_MSEC(PECI_TIMEOUT_MS)); + + if (ret == -EAGAIN) { + LOG_ERR("%s: Timeout", __func__); + return -ETIMEDOUT; + } + + if (peci_regs->HOSTAR != FINISH) { + LOG_ERR("[PECI] Error: HOSTAR=0x%02X\r\n", peci_regs->HOSTAR); + return -EIO; + } + + return 0; +} + +static int peci_it8xxx2_configure(const struct device *dev, uint32_t bitrate) +{ + struct peci_it8xxx2_data *data = dev->data; + const struct peci_it8xxx2_config *config = dev->config; + struct peci_it8xxx2_regs *const peci_regs = + (struct peci_it8xxx2_regs *)config->base_addr; + + uint8_t hoctl2r_to_write; + + data->bitrate = bitrate; + + hoctl2r_to_write = + (peci_regs->HOCTL2R) & (~(PECI_IT8XXX2_BITRATE_BITS_MASK)); + + switch (bitrate) { + case PECI_IT8XXX2_BITRATE_2MHZ: + break; + + case PECI_IT8XXX2_BITRATE_1MHZ: + hoctl2r_to_write |= PECI_IT8XXX2_BITRATE_1MHZ_BITS; + break; + + case PECI_IT8XXX2_BITRATE_1P6MHZ: + hoctl2r_to_write |= PECI_IT8XXX2_BITRATE_1P6MHZ_BITS; + break; + + default: + LOG_ERR("[PECI] Error: Specified Bitrate Not Supported\r\n"); + hoctl2r_to_write |= PECI_IT8XXX2_BITRATE_1MHZ_BITS; + data->bitrate = PECI_IT8XXX2_BITRATE_1MHZ; + peci_regs->HOCTL2R = hoctl2r_to_write; + return -ENOTSUP; + } + + peci_regs->HOCTL2R = hoctl2r_to_write; + + return 0; +} + +static int peci_it8xxx2_enable(const struct device *dev) +{ + const struct peci_it8xxx2_config *config = dev->config; + struct peci_it8xxx2_regs *const peci_regs = + (struct peci_it8xxx2_regs *)config->base_addr; + + peci_regs->HOCTLR |= (FIFOCLR|FCSERR_ABT|PECIHEN|CONTROL); + + return 0; +} + +static int peci_it8xxx2_disable(const struct device *dev) +{ + const struct peci_it8xxx2_config *config = dev->config; + struct peci_it8xxx2_regs *const peci_regs = + (struct peci_it8xxx2_regs *)config->base_addr; + + peci_regs->HOCTLR &= ~(PECIHEN); + return 0; +} + +static void peci_it8xxx2_rst_module(const struct device *dev) +{ + const struct peci_it8xxx2_config *config = dev->config; + struct peci_it8xxx2_regs *const peci_regs = + (struct peci_it8xxx2_regs *)config->base_addr; + + LOG_ERR("[PECI] Module Reset for Status Error.\r\n"); + /* Reset IT8XXX2 PECI Module Thoroughly */ + IT83XX_GCTRL_RSTC4 |= RPECI; + /* + * Due to the fact that we've checked if the peci_enable() + * called before calling the peci_transfer(), so the peci + * were definitely enabled before the error occurred. + * Here is the recovery mechanism for recovering the PECI + * bus when the errors occur. + */ + peci_regs->PADCTLR |= PECI_DVIE; + peci_it8xxx2_init_vtts(peci_regs, HOVTTS0P95V); + peci_it8xxx2_configure(dev, PECI_IT8XXX2_BITRATE_1MHZ); + peci_it8xxx2_enable(dev); + LOG_ERR("[PECI] Reinitialization Finished.\r\n"); +} + +static int peci_it8xxx2_transfer(const struct device *dev, struct peci_msg *msg) +{ + const struct peci_it8xxx2_config *config = dev->config; + struct peci_it8xxx2_regs *const peci_regs = + (struct peci_it8xxx2_regs *)config->base_addr; + + struct peci_buf *peci_rx_buf = &msg->rx_buffer; + struct peci_buf *peci_tx_buf = &msg->tx_buffer; + + int cnt, ret_code; + + ret_code = 0; + + if (!(peci_regs->HOCTLR & PECIHEN)) { + LOG_ERR("[PECI] Please call the peci_enable() first.\r\n"); + return -ECONNREFUSED; + } + + if (peci_it8xxx2_check_host_busy(peci_regs) != 0) { + return -EBUSY; + } + + peci_regs->HOTRADDR = msg->addr; + peci_regs->HOWRLR = peci_tx_buf->len; + peci_regs->HORDLR = peci_rx_buf->len; + peci_regs->HOCMDR = msg->cmd_code; + + if (msg->cmd_code != PECI_CMD_PING) { + for (cnt = 0; cnt < (peci_tx_buf->len - 1); cnt++) { + peci_regs->HOWRDR = peci_tx_buf->buf[cnt]; + } + } + + /* Host Available */ + irq_enable(config->irq_no); + peci_regs->HOCTLR |= START; + ret_code = peci_it8xxx2_check_host_finish(dev); + + if (!ret_code) { + /* Host Transactions Finished, Fetch Data from the regs */ + if (peci_rx_buf->len) { + for (cnt = 0; cnt < (peci_rx_buf->len); cnt++) { + peci_rx_buf->buf[cnt] = peci_regs->HORDDR; + } + } + peci_it8xxx2_rst_status(peci_regs); + + } else { + /* Host Transactions Failure */ + peci_it8xxx2_rst_module(dev); + } + + return (ret_code); +} + +static void peci_it8xxx2_isr(const struct device *dev) +{ + struct peci_it8xxx2_data *data = dev->data; + const struct peci_it8xxx2_config *config = dev->config; + + irq_disable(config->irq_no); + k_sem_give(&data->device_sync_sem); +} + +static const struct peci_driver_api peci_it8xxx2_driver_api = { + .config = peci_it8xxx2_configure, + .enable = peci_it8xxx2_enable, + .disable = peci_it8xxx2_disable, + .transfer = peci_it8xxx2_transfer, +}; + +static int peci_it8xxx2_init(const struct device *dev) +{ + struct peci_it8xxx2_data *data = dev->data; + const struct peci_it8xxx2_config *config = dev->config; + struct peci_it8xxx2_regs *const peci_regs = + (struct peci_it8xxx2_regs *)config->base_addr; + + /* Initialize Semaphore */ + k_sem_init(&data->device_sync_sem, 0, 1); + + /* Configure the GPF6 to Alternative Function 3: PECI */ + pinmux_pin_set(config->alts_list[PECI0].pinctrls, + config->alts_list[PECI0].pin, + config->alts_list[PECI0].alt_fun); + + peci_regs->PADCTLR |= PECI_DVIE; + peci_it8xxx2_init_vtts(peci_regs, HOVTTS0P95V); + peci_it8xxx2_configure(dev, PECI_IT8XXX2_BITRATE_1MHZ); + + /* Interrupt Assignment */ + IRQ_CONNECT(DT_INST_IRQN(0), + 0, + peci_it8xxx2_isr, + DEVICE_DT_INST_GET(0), + 0); + + return 0; +} + +DEVICE_DT_INST_DEFINE(0, + &peci_it8xxx2_init, + NULL, + &peci_it8xxx2_data0, + &peci_it8xxx2_config0, + POST_KERNEL, CONFIG_PECI_INIT_PRIORITY, + &peci_it8xxx2_driver_api); diff --git a/dts/bindings/peci/ite,it8xxx2-peci.yaml b/dts/bindings/peci/ite,it8xxx2-peci.yaml new file mode 100644 index 00000000000..23085908c82 --- /dev/null +++ b/dts/bindings/peci/ite,it8xxx2-peci.yaml @@ -0,0 +1,14 @@ +# Copyright (c) 2022 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +description: ITE it8xxx2 PECI + +compatible: "ite,peci-it8xxx2" + +include: peci.yaml + +properties: + pinctrl-0: + type: phandles + required: true + description: Configuration of the PECI pin which is mapped to the GPIO diff --git a/dts/riscv/it8xxx2-alts-map.dtsi b/dts/riscv/it8xxx2-alts-map.dtsi index 21cd39e8cae..7d498cd6b96 100644 --- a/dts/riscv/it8xxx2-alts-map.dtsi +++ b/dts/riscv/it8xxx2-alts-map.dtsi @@ -134,6 +134,11 @@ pinctrls = <&pinmuxm 5 IT8XXX2_PINMUX_FUNC_1>; }; + /* PECI alternate function */ + pinctrl_peci: peci { + pinctrls = <&pinmuxf 6 IT8XXX2_PINMUX_FUNC_3>; + }; + /* Keyboard alternate function */ pinctrl_kso16: kso16 { pinctrls = <&pinmuxc 3 IT8XXX2_PINMUX_FUNC_1>; diff --git a/dts/riscv/it8xxx2.dtsi b/dts/riscv/it8xxx2.dtsi index 20777af31bc..218f32358f9 100644 --- a/dts/riscv/it8xxx2.dtsi +++ b/dts/riscv/it8xxx2.dtsi @@ -885,6 +885,17 @@ label = "GCTRL"; }; + peci0: peci@f02c00 { + compatible = "ite,peci-it8xxx2"; + reg = <0x00f02c00 15>; + label = "PECI_0"; + #address-cells=<1>; + #size-cells = <0>; + interrupt-parent = <&intc>; + interrupts = <160 IRQ_TYPE_LEVEL_HIGH>; + pinctrl-0 = <&pinctrl_peci>; + }; + kscan0: kscan@f01d00 { compatible = "ite,it8xxx2-kscan"; reg = <0x00f01d00 0x29 diff --git a/soc/riscv/riscv-ite/common/check_regs.c b/soc/riscv/riscv-ite/common/check_regs.c index 4350ad84c68..ccbbcce1901 100644 --- a/soc/riscv/riscv-ite/common/check_regs.c +++ b/soc/riscv/riscv-ite/common/check_regs.c @@ -78,6 +78,23 @@ IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_P80HDR, 0x51); IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_H2ROFSR, 0x53); IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_ECHIPID2, 0x86); +/* PECI register structure check */ +IT8XXX2_REG_SIZE_CHECK(peci_it8xxx2_regs, 0x0F); +IT8XXX2_REG_OFFSET_CHECK(peci_it8xxx2_regs, HOSTAR, 0x00); +IT8XXX2_REG_OFFSET_CHECK(peci_it8xxx2_regs, HOCTLR, 0x01); +IT8XXX2_REG_OFFSET_CHECK(peci_it8xxx2_regs, HOCMDR, 0x02); +IT8XXX2_REG_OFFSET_CHECK(peci_it8xxx2_regs, HOTRADDR, 0x03); +IT8XXX2_REG_OFFSET_CHECK(peci_it8xxx2_regs, HOWRLR, 0x04); +IT8XXX2_REG_OFFSET_CHECK(peci_it8xxx2_regs, HORDLR, 0x05); +IT8XXX2_REG_OFFSET_CHECK(peci_it8xxx2_regs, HOWRDR, 0x06); +IT8XXX2_REG_OFFSET_CHECK(peci_it8xxx2_regs, HORDDR, 0x07); +IT8XXX2_REG_OFFSET_CHECK(peci_it8xxx2_regs, HOCTL2R, 0x08); +IT8XXX2_REG_OFFSET_CHECK(peci_it8xxx2_regs, RWFCSV, 0x09); +IT8XXX2_REG_OFFSET_CHECK(peci_it8xxx2_regs, RRFCSV, 0x0A); +IT8XXX2_REG_OFFSET_CHECK(peci_it8xxx2_regs, WFCSV, 0x0B); +IT8XXX2_REG_OFFSET_CHECK(peci_it8xxx2_regs, RFCSV, 0x0C); +IT8XXX2_REG_OFFSET_CHECK(peci_it8xxx2_regs, AWFCSV, 0x0D); +IT8XXX2_REG_OFFSET_CHECK(peci_it8xxx2_regs, PADCTLR, 0x0E); /* KSCAN register structure check */ IT8XXX2_REG_SIZE_CHECK(kscan_it8xxx2_regs, 0x0F); IT8XXX2_REG_OFFSET_CHECK(kscan_it8xxx2_regs, KBS_KSOL, 0x00); diff --git a/soc/riscv/riscv-ite/common/chip_chipregs.h b/soc/riscv/riscv-ite/common/chip_chipregs.h index 988c6b7ad50..de55a6c890e 100644 --- a/soc/riscv/riscv-ite/common/chip_chipregs.h +++ b/soc/riscv/riscv-ite/common/chip_chipregs.h @@ -1372,39 +1372,43 @@ enum ext_timer_idx { #define TMRCE ECREG(EC_REG_BASE_ADDR + 0x290B) #define TMEIE ECREG(EC_REG_BASE_ADDR + 0x290C) -/** - * +/* * (2Cxxh) Platform Environment Control Interface (PECI) - * */ -#define HOSTAR ECREG(EC_REG_BASE_ADDR + 0x2C00) -#define TEMPERR BIT(7) -#define BUSERR BIT(6) -#define EXTERR BIT(5) -#define WR_FCS_ERR BIT(3) -#define RD_FCS_ERR BIT(2) -#define FINISH BIT(1) -#define HOBY BIT(0) -#define HOCTLR ECREG(EC_REG_BASE_ADDR + 0x2C01) -#define FIFOCLR BIT(5) -#define FCSERR_ABT BIT(4) -#define PECIHEN BIT(3) -#define CONCTRL BIT(2) -#define AWFCS_EN BIT(1) -#define PECISTART BIT(0) -#define HOCMDR ECREG(EC_REG_BASE_ADDR + 0x2C02) -#define HOTRADDR ECREG(EC_REG_BASE_ADDR + 0x2C03) -#define HOWRLR ECREG(EC_REG_BASE_ADDR + 0x2C04) -#define HORDLR ECREG(EC_REG_BASE_ADDR + 0x2C05) -#define HOWRDR ECREG(EC_REG_BASE_ADDR + 0x2C06) -#define HORDDR ECREG(EC_REG_BASE_ADDR + 0x2C07) -#define HOCTL2R ECREG(EC_REG_BASE_ADDR + 0x2C08) -#define RWFCSV ECREG(EC_REG_BASE_ADDR + 0x2C09) -#define RRFCSV ECREG(EC_REG_BASE_ADDR + 0x2C0A) -#define WFCSV ECREG(EC_REG_BASE_ADDR + 0x2C0B) -#define RFCSV ECREG(EC_REG_BASE_ADDR + 0x2C0C) -#define AWFCSV ECREG(EC_REG_BASE_ADDR + 0x2C0D) -#define PADCTLR ECREG(EC_REG_BASE_ADDR + 0x2C0E) +#ifndef __ASSEMBLER__ +struct peci_it8xxx2_regs { + /* 0x00: Host Status */ + volatile uint8_t HOSTAR; + /* 0x01: Host Control */ + volatile uint8_t HOCTLR; + /* 0x02: Host Command */ + volatile uint8_t HOCMDR; + /* 0x03: Host Target Address */ + volatile uint8_t HOTRADDR; + /* 0x04: Host Write Length */ + volatile uint8_t HOWRLR; + /* 0x05: Host Read Length */ + volatile uint8_t HORDLR; + /* 0x06: Host Write Data */ + volatile uint8_t HOWRDR; + /* 0x07: Host Read Data */ + volatile uint8_t HORDDR; + /* 0x08: Host Control 2 */ + volatile uint8_t HOCTL2R; + /* 0x09: Received Write FCS value */ + volatile uint8_t RWFCSV; + /* 0x0A: Received Read FCS value */ + volatile uint8_t RRFCSV; + /* 0x0B: Write FCS Value */ + volatile uint8_t WFCSV; + /* 0x0C: Read FCS Value */ + volatile uint8_t RFCSV; + /* 0x0D: Assured Write FCS Value */ + volatile uint8_t AWFCSV; + /* 0x0E: Pad Control */ + volatile uint8_t PADCTLR; +}; +#endif /* !__ASSEMBLER__ */ /** * diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.series b/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.series index 14fb8dd4085..417796a7c1f 100644 --- a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.series +++ b/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.series @@ -76,6 +76,11 @@ config TACH_IT8XXX2 default y depends on SENSOR +config PECI_ITE_IT8XXX2 + default y + depends on PECI + select PECI_INTERRUPT_DRIVEN + if ITE_IT8XXX2_INTC config NUM_IRQS default 185