diff --git a/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts b/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts index a9174eeb1be..198acaf45d3 100644 --- a/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts +++ b/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts @@ -23,6 +23,11 @@ clock-frequency = <96000000>; }; +/* Initialize ECIA. Does not initialize child devices */ +&ecia { + status = "okay"; +}; + &systick { status = "okay"; }; @@ -33,4 +38,5 @@ &uart1 { status = "okay"; + current-speed = <115200>; }; diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index d0af18e5f8b..35cf4b56578 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -21,3 +21,4 @@ zephyr_sources_ifdef(CONFIG_NPCX_MIWU intc_miwu.c) zephyr_sources_ifdef(CONFIG_LEON_IRQMP intc_irqmp.c) zephyr_sources_ifdef(CONFIG_INTEL_VTD_ICTL intc_intel_vtd.c) zephyr_sources_ifdef(CONFIG_SOC_ESP32 intc_esp32.c) +zephyr_sources_ifdef(CONFIG_MCHP_ECIA_XEC intc_mchp_ecia_xec.c) diff --git a/drivers/interrupt_controller/Kconfig b/drivers/interrupt_controller/Kconfig index bdace97c5ea..7a297f8dce7 100644 --- a/drivers/interrupt_controller/Kconfig +++ b/drivers/interrupt_controller/Kconfig @@ -70,4 +70,6 @@ source "drivers/interrupt_controller/Kconfig.intel_vtd" source "drivers/interrupt_controller/Kconfig.esp32" +source "drivers/interrupt_controller/Kconfig.xec" + endmenu diff --git a/drivers/interrupt_controller/Kconfig.xec b/drivers/interrupt_controller/Kconfig.xec new file mode 100644 index 00000000000..cd872d0c175 --- /dev/null +++ b/drivers/interrupt_controller/Kconfig.xec @@ -0,0 +1,11 @@ +# Microchip XEC ECIA configuration + +# Copyright (c) 2021 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config MCHP_ECIA_XEC + bool "External EC Interrupt Aggregator (ECIA) Driver for MCHP MEC family of MCUs" + default y + depends on SOC_SERIES_MEC172X + help + Enable XEC ECIA driver for Microchip MEC line of MCUs diff --git a/drivers/interrupt_controller/intc_mchp_ecia_xec.c b/drivers/interrupt_controller/intc_mchp_ecia_xec.c new file mode 100644 index 00000000000..b364945a0e7 --- /dev/null +++ b/drivers/interrupt_controller/intc_mchp_ecia_xec.c @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2021 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Driver for External interrupt controller in Microchip XEC devices + * + * Driver is currently implemented to support MEC172x ECIA GIRQs + */ + +#define DT_DRV_COMPAT microchip_xec_ecia + +#include +#include +#include +#include +#include +#include +#include + +/* defined at the SoC layer */ +#define MCHP_FIRST_GIRQ MCHP_FIRST_GIRQ_NOS +#define MCHP_LAST_GIRQ MCHP_LAST_GIRQ_NOS +#define MCHP_XEC_DIRECT_CAPABLE MCHP_ECIA_DIRECT_BITMAP + +#define GIRQ_ID_TO_BITPOS(id) ((id) + 8) + +/* + * MEC SoC's have one and only one instance of ECIA. GIRQ8 register are located + * at the beginning of the ECIA block. + */ +#define ECIA_XEC_REG_BASE \ + ((struct ecia_regs *)(DT_REG_ADDR(DT_NODELABEL(ecia)))) + +#define ECS_XEC_REG_BASE \ + ((struct ecs_regs *)(DT_REG_ADDR(DT_NODELABEL(ecs)))) + +#define PCR_XEC_REG_BASE \ + ((struct pcr_regs *)(DT_REG_ADDR(DT_NODELABEL(pcr)))) + +#define ECIA_XEC_PCR_REG_IDX DT_INST_CLOCKS_CELL(0, regidx) +#define ECIA_XEC_PCR_BITPOS DT_INST_CLOCKS_CELL(0, bitpos) + +#define ECIA_XEC_PCR_INFO \ + MCHP_XEC_PCR_SCR_ENCODE(DT_INST_CLOCKS_CELL(0, regidx), \ + DT_INST_CLOCKS_CELL(0, bitpos)) + +struct xec_girq_config { + uintptr_t base; + uint8_t girq_id; + uint8_t num_srcs; + uint8_t sources[32]; +}; + +struct xec_ecia_config { + uintptr_t ecia_base; + struct mchp_xec_pcr_clk_ctrl clk_ctrl; + const struct device *girq_node_handles[32]; +}; + +struct xec_girq_src_data { + mchp_xec_ecia_callback_t cb; + void *data; +}; + +#define DEV_ECIA_CFG(ecia_dev) \ + ((const struct xec_ecia_config *const)(ecia_dev)->config) + +#define DEV_GIRQ_CFG(girq_dev) \ + ((const struct xec_girq_config *const)(girq_dev)->config) + +#define DEV_GIRQ_DATA(girq_dev) \ + ((struct xec_girq_src_data *const)(girq_dev)->data) + +/* + * Enable/disable specified GIRQ's aggregated output. Aggrated output is the + * bit-wise or of all the GIRQ's result bits. + */ +void mchp_xec_ecia_girq_aggr_en(uint8_t girq_num, uint8_t enable) +{ + struct ecia_regs *regs = ECIA_XEC_REG_BASE; + + if (enable) { + regs->BLK_EN_SET = BIT(girq_num); + } else { + regs->BLK_EN_CLR = BIT(girq_num); + } +} + +void mchp_xec_ecia_girq_src_clr(uint8_t girq_num, uint8_t src_bit_pos) +{ + if ((girq_num < MCHP_FIRST_GIRQ) || (girq_num > MCHP_LAST_GIRQ)) { + return; + } + + struct ecia_regs *regs = ECIA_XEC_REG_BASE; + + /* write 1 to clear */ + regs->GIRQ[girq_num - MCHP_FIRST_GIRQ].SRC = BIT(src_bit_pos); +} + +void mchp_xec_ecia_girq_src_en(uint8_t girq_num, uint8_t src_bit_pos) +{ + if ((girq_num < MCHP_FIRST_GIRQ) || (girq_num > MCHP_LAST_GIRQ)) { + return; + } + + struct ecia_regs *regs = ECIA_XEC_REG_BASE; + + /* write 1 to set */ + regs->GIRQ[girq_num - MCHP_FIRST_GIRQ].EN_SET = BIT(src_bit_pos); +} + +void mchp_xec_ecia_girq_src_dis(uint8_t girq_num, uint8_t src_bit_pos) +{ + if ((girq_num < MCHP_FIRST_GIRQ) || (girq_num > MCHP_LAST_GIRQ)) { + return; + } + + struct ecia_regs *regs = ECIA_XEC_REG_BASE; + + /* write 1 to clear */ + regs->GIRQ[girq_num - MCHP_FIRST_GIRQ].EN_CLR = BIT(src_bit_pos); +} + +void mchp_xec_ecia_girq_src_clr_bitmap(uint8_t girq_num, uint32_t bitmap) +{ + if ((girq_num < MCHP_FIRST_GIRQ) || (girq_num > MCHP_LAST_GIRQ)) { + return; + } + + struct ecia_regs *regs = ECIA_XEC_REG_BASE; + + /* write 1 to clear */ + regs->GIRQ[girq_num - MCHP_FIRST_GIRQ].SRC = bitmap; +} + +void mchp_xec_ecia_girq_src_en_bitmap(uint8_t girq_num, uint32_t bitmap) +{ + if ((girq_num < MCHP_FIRST_GIRQ) || (girq_num > MCHP_LAST_GIRQ)) { + return; + } + + struct ecia_regs *regs = ECIA_XEC_REG_BASE; + + /* write 1 to clear */ + regs->GIRQ[girq_num - MCHP_FIRST_GIRQ].EN_SET = bitmap; +} + +void mchp_xec_ecia_girq_src_dis_bitmap(uint8_t girq_num, uint32_t bitmap) +{ + if ((girq_num < MCHP_FIRST_GIRQ) || (girq_num > MCHP_LAST_GIRQ)) { + return; + } + + struct ecia_regs *regs = ECIA_XEC_REG_BASE; + + /* write 1 to clear */ + regs->GIRQ[girq_num - MCHP_FIRST_GIRQ].EN_CLR = bitmap; +} + +/* + * Return read-only GIRQ result register. Result is bit-wise and of source + * and enable registers. + */ +uint32_t mchp_xec_ecia_girq_result(uint8_t girq_num) +{ + if ((girq_num < MCHP_FIRST_GIRQ) || (girq_num > MCHP_LAST_GIRQ)) { + return 0U; + } + + struct ecia_regs *regs = ECIA_XEC_REG_BASE; + + return regs->GIRQ[girq_num - MCHP_FIRST_GIRQ].RESULT; +} + +/* Clear NVIC pending given the external NVIC input number (zero based) */ +void mchp_xec_ecia_nvic_clr_pend(uint32_t nvic_num) +{ + if (nvic_num >= ((SCnSCB->ICTR + 1) * 32)) { + return; + } + + NVIC_ClearPendingIRQ(nvic_num); +} + +/** + * @brief enable GIRQn interrupt for specific source + * + * @param girq is the GIRQ number (8 - 26) + * @param src is the interrupt source in the GIRQ (0 - 31) + */ +int mchp_xec_ecia_enable(int girq, int src) +{ + if ((girq < MCHP_FIRST_GIRQ) || (girq > MCHP_LAST_GIRQ) || + (src < 0) || (src > 31)) { + return -EINVAL; + } + + struct ecia_regs *regs = ECIA_XEC_REG_BASE; + + /* write 1 to set */ + regs->GIRQ[girq - MCHP_FIRST_GIRQ].EN_SET = BIT(src); + + return 0; +} + +/** + * @brief disable EXTI interrupt for specific line + * + * @param girq is the GIRQ number (8 - 26) + * @param src is the interrupt source in the GIRQ (0 - 31) + */ +int mchp_xec_ecia_disable(int girq, int src) +{ + if ((girq < MCHP_FIRST_GIRQ) || (girq > MCHP_LAST_GIRQ) || + (src < 0) || (src > 31)) { + return -EINVAL; + } + + struct ecia_regs *regs = ECIA_XEC_REG_BASE; + + /* write 1 to clear */ + regs->GIRQ[girq - MCHP_FIRST_GIRQ].EN_CLR = BIT(src); + + return 0; +} + +/* forward reference */ +static const struct device *get_girq_dev(int girq_num); + +/** + * @brief set GIRQn interrupt source callback + * + * @param dev_girq is the GIRQn device handle + * @param src is the interrupt source in the GIRQ (0 - 31) + * @param cb user callback + * @param data user data + */ +int mchp_xec_ecia_set_callback_by_dev(const struct device *dev_girq, int src, + mchp_xec_ecia_callback_t cb, void *data) +{ + if ((dev_girq == NULL) || (src < 0) || (src > 31)) { + return -EINVAL; + } + + const struct xec_girq_config *const cfg = DEV_GIRQ_CFG(dev_girq); + struct xec_girq_src_data *girq_data = DEV_GIRQ_DATA(dev_girq); + + /* source exists in this GIRQ? */ + if (!(cfg->sources[src] & BIT(7))) { + return -EINVAL; + } + + /* obtain the callback array index for the source */ + int idx = (int)(cfg->sources[src] & ~BIT(7)); + + girq_data[idx].cb = cb; + girq_data[idx].data = data; + + return 0; +} + +/** + * @brief set GIRQn interrupt source callback + * + * @param girq is the GIRQ number (8 - 26) + * @param src is the interrupt source in the GIRQ (0 - 31) + * @param cb user callback + * @param data user data + */ +int mchp_xec_ecia_set_callback(int girq_num, int src, + mchp_xec_ecia_callback_t cb, void *data) +{ + const struct device *dev = get_girq_dev(girq_num); + + return mchp_xec_ecia_set_callback_by_dev(dev, src, cb, data); +} + +/** + * @brief unset GIRQn interrupt source callback by device handle + * + * @param dev_girq is the GIRQn device handle + * @param src is the interrupt source in the GIRQ (0 - 31) + */ +int mchp_ecia_unset_callback_by_dev(const struct device *dev_girq, int src) +{ + if ((dev_girq == NULL) || (src < 0) || (src > 31)) { + return -EINVAL; + } + + const struct xec_girq_config *const cfg = DEV_GIRQ_CFG(dev_girq); + struct xec_girq_src_data *girq_data = DEV_GIRQ_DATA(dev_girq); + + /* source exists in this GIRQ? */ + if (!(cfg->sources[src] & BIT(7))) { + return -EINVAL; + } + + /* obtain the callback array index for the source */ + int idx = (int)(cfg->sources[src] & ~BIT(7)); + + girq_data[idx].cb = NULL; + girq_data[idx].data = NULL; + + return 0; +} + +/** + * @brief unset GIRQn interrupt source callback + * + * @param girq is the GIRQ number (8 - 26) + * @param src is the interrupt source in the GIRQ (0 - 31) + */ +int mchp_ecia_unset_callback(int girq_num, int src) +{ + const struct device *dev = get_girq_dev(girq_num); + + return mchp_ecia_unset_callback_by_dev(dev, src); +} + +/* + * Create a build time flag to know if any aggregated GIRQ has been enabled. + * We make use of DT FOREACH macro to check GIRQ node status. + * Enabling a GIRQ node (status = "okay") implies you want it used in + * aggregated mode. Note, GIRQ 8-12, 24-26 are aggregated only by HW design. + * If a GIRQ node is disabled(status = "disabled") and is direct capable the + * other driver/application may use IRQ_CONNECT, irq_enable, and the helper + * functions in this driver to set/clear GIRQ enable bits and status. + * Leaving a node disabled also allows another driver/application to take over + * aggregation by managing the GIRQ itself. + */ +#define XEC_CHK_REQ_AGGR(n) DT_NODE_HAS_STATUS(n, okay) | + +#define XEC_ECIA_REQUIRE_AGGR_ISR \ + ( \ + DT_FOREACH_CHILD(DT_NODELABEL(ecia), XEC_CHK_REQ_AGGR) \ + 0) + +/* static const uint32_t xec_chk_req = (XEC_ECIA_REQUIRE_AGGR_ISR); */ + +#if XEC_ECIA_REQUIRE_AGGR_ISR +/* + * Generic ISR for aggregated GIRQ's. + * GIRQ source(status) bits are latched (R/W1C). The peripheral status + * connected to the GIRQ source bit must be cleared first by the callback + * and this routine will clear the GIRQ source bit. If a callback was not + * registered for a source the enable will also be cleared to prevent + * interrupt storms. + * NOTE: dev_girq is a pointer to a GIRQ child device instance. + */ +static void xec_girq_isr(const struct device *dev_girq) +{ + const struct xec_girq_config *const cfg = DEV_GIRQ_CFG(dev_girq); + struct xec_girq_src_data *data = DEV_GIRQ_DATA(dev_girq); + struct girq_regs *girq = (struct girq_regs *)cfg->base; + int girq_id = GIRQ_ID_TO_BITPOS(cfg->girq_id); + uint32_t idx = 0; + uint32_t result = girq->RESULT; + + for (int i = 0; result && i < 32; i++) { + uint8_t bitpos = 31 - (__builtin_clz(result) & 0x1f); + + /* is it an implemented source? */ + if (cfg->sources[bitpos] & BIT(7)) { + /* yes, get the index by removing bit[7] flag */ + idx = (uint32_t)cfg->sources[bitpos] & ~BIT(7); + /* callback registered? */ + if (data[idx].cb) { + data[idx].cb(girq_id, bitpos, data[idx].data); + } else { /* no callback, clear the enable */ + girq->EN_CLR = BIT(bitpos); + } + } else { /* paranoia, we should not get here... */ + girq->EN_CLR = BIT(bitpos); + } + + /* clear GIRQ latched status */ + girq->SRC = BIT(bitpos); + result &= ~BIT(bitpos); + } +} +#endif + +/** + * @brief initialize XEC ECIA driver + * NOTE: GIRQ22 is special used for waking the PLL from deep sleep when a + * peripheral receives data from an external entity (eSPI, I2C, etc). Once + * the data transfer is complete the system re-enters deep sleep unless the + * peripheral was configured to wake CPU after reception of data or event. + * GIRQ22 aggregated output and sources are not connected to the NVIC. + * We enable GIRQ22 aggregated output to ensure clock asynchronous wake + * functionality is operational. + */ +static int xec_ecia_init(const struct device *dev) +{ + const struct xec_ecia_config *cfg = + (const struct xec_ecia_config *const) (dev->config); + const struct device *const clk_dev = DEVICE_DT_GET(DT_NODELABEL(pcr)); + struct ecs_regs *const ecs = ECS_XEC_REG_BASE; + struct ecia_regs *const ecia = (struct ecia_regs *)cfg->ecia_base; + uint32_t n = 0, nr = 0; + int ret; + + ret = clock_control_on(clk_dev, + (clock_control_subsys_t *)&cfg->clk_ctrl); + if (ret < 0) { + return ret; + } + + /* Enable all direct NVIC connections */ + ecs->INTR_CTRL |= BIT(0); + + /* gate off all aggregated outputs */ + ecia->BLK_EN_CLR = UINT32_MAX; + + /* connect aggregated only GIRQs to NVIC */ + ecia->BLK_EN_SET = MCHP_ECIA_AGGR_BITMAP; + + /* Clear all GIRQn source enables */ + for (n = 0; n < MCHP_GIRQS; n++) { + ecia->GIRQ[n].EN_CLR = UINT32_MAX; + } + + /* Clear all external NVIC enables and pending status */ + nr = SCnSCB->ICTR; + for (n = 0u; n <= nr; n++) { + NVIC->ICER[n] = UINT32_MAX; + NVIC->ICPR[n] = UINT32_MAX; + } + + /* ecia->BLK_ACTIVE = xec_chk_req; */ + + return 0; +} + +/* xec_config_girq_xxx.sources[] entries from GIRQ node */ +#define XEC_GIRQ_SOURCES2(node_id, prop, idx) \ + .sources[DT_PROP_BY_IDX(node_id, prop, idx)] = \ + ((uint8_t)(idx) | BIT(7)), + +/* Parameter n is a child node-id */ +#define GIRQ_XEC_DEVICE(n) \ + static int xec_girq_init_##n(const struct device *dev); \ + \ + static struct xec_girq_src_data \ + xec_data_girq_##n[DT_PROP_LEN(n, sources)]; \ + \ + static const struct xec_girq_config xec_config_girq_##n = { \ + .base = DT_REG_ADDR(n), \ + .girq_id = DT_PROP(n, girq_id), \ + .num_srcs = DT_PROP_LEN(n, sources), \ + DT_FOREACH_PROP_ELEM(n, sources, XEC_GIRQ_SOURCES2) \ + }; \ + \ + DEVICE_DT_DEFINE(n, xec_girq_init_##n, \ + NULL, &xec_data_girq_##n, &xec_config_girq_##n, \ + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + NULL); \ + \ + static int xec_girq_init_##n(const struct device *dev) \ + { \ + mchp_xec_ecia_girq_aggr_en( \ + GIRQ_ID_TO_BITPOS(DT_PROP(n, girq_id)), 1); \ + \ + IRQ_CONNECT(DT_IRQN(n), \ + DT_IRQ(n, priority), \ + xec_girq_isr, \ + DEVICE_DT_GET(n), 0); \ + \ + irq_enable(DT_IRQN(n)); \ + \ + return 0; \ + } + +/* + * iterate over each enabled child node of ECIA + * Enable means property status = "okay" + */ +DT_FOREACH_CHILD_STATUS_OKAY(DT_NODELABEL(ecia), GIRQ_XEC_DEVICE) + +/* n = GIRQ node id */ +#define XEC_GIRQ_HANDLE(n) \ + .girq_node_handles[DT_PROP(n, girq_id)] = (DEVICE_DT_GET(n)), + +static const struct xec_ecia_config xec_config_ecia = { + .ecia_base = DT_REG_ADDR(DT_NODELABEL(ecia)), + .clk_ctrl = { + .pcr_info = ECIA_XEC_PCR_INFO, + }, + DT_FOREACH_CHILD_STATUS_OKAY(DT_NODELABEL(ecia), XEC_GIRQ_HANDLE) +}; + +DEVICE_DT_DEFINE(DT_NODELABEL(ecia), xec_ecia_init, + NULL, NULL, &xec_config_ecia, + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, + NULL); + +/* look up GIRQ node handle from ECIA configuration */ +static const struct device *get_girq_dev(int girq_num) +{ + if ((girq_num < MCHP_FIRST_GIRQ) || (girq_num > MCHP_LAST_GIRQ)) { + return NULL; + } + + /* safe to convert to zero based index */ + girq_num -= MCHP_FIRST_GIRQ; + + return xec_config_ecia.girq_node_handles[girq_num]; +} diff --git a/dts/arm/microchip/mec172xnsz.dtsi b/dts/arm/microchip/mec172xnsz.dtsi index c43c8ecdf60..c5722b1501d 100644 --- a/dts/arm/microchip/mec172xnsz.dtsi +++ b/dts/arm/microchip/mec172xnsz.dtsi @@ -9,6 +9,7 @@ #include #include #include +#include / { cpus { @@ -47,9 +48,213 @@ periph-32k-src = ; #clock-cells = <2>; }; - girq23: girq23@4000e12c { - reg = <0x4000e12c 0x14>; - label = "GIRQ_23"; + ecia: ecia@4000e000 { + compatible = "microchip,xec-ecia"; + reg = <0x4000e000 0x400>; + direct-capable-girqs = <13 14 15 16 17 18 19 20 21 23>; + clocks = <&pcr 1 0>; + label = "ECIA_0"; + #address-cells = <1>; + #size-cells = <1>; + + ranges = <0x0 0x4000e000 0x400>; + + girq8: girq8@0 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x0 0x14>; + interrupts = <0 0>; + label = "GIRQ_8"; + girq-id = <0>; + sources = <0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 21 22 24 25 + 26 27 28 29>; + status = "disabled"; + }; + girq9: girq9@14 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x14 0x14>; + interrupts = <1 0>; + label = "GIRQ_9"; + girq-id = <1>; + sources = <0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 19 20 21 22 23 + 24 25 26 27 28 29>; + status = "disabled"; + }; + girq10: girq10@28 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x28 0x14>; + interrupts = <2 0>; + label = "GIRQ_10"; + girq-id = <2>; + sources = <0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 19 20 21 22 23 + 24 25 26 27 28 29 30>; + status = "disabled"; + }; + girq11: girq11@3c { + compatible = "microchip,xec-ecia-girq"; + reg = <0x3c 0x14>; + interrupts = <3 0>; + label = "GIRQ_11"; + girq-id = <3>; + sources = <0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 19 20 21 22 23 + 24 25 26 27 28 29 30>; + status = "disabled"; + }; + girq12: girq12@50 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x50 0x14>; + interrupts = <4 0>; + label = "GIRQ_12"; + girq-id = <4>; + sources = <0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 19 20 21 22 23 + 24 25 26 27 28 29 30>; + status = "disabled"; + }; + girq13: girq13@64 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x64 0x14>; + interrupts = <5 0>; + label = "GIRQ_13"; + girq-id = <5>; + sources = <0 1 2 3 4>; + status = "disabled"; + }; + girq14: girq14@78 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x78 0x14>; + interrupts = <6 0>; + label = "GIRQ_14"; + girq-id = <6>; + sources = <0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15>; + status = "disabled"; + }; + girq15: girq15@8c { + compatible = "microchip,xec-ecia-girq"; + reg = <0x8c 0x14>; + interrupts = <7 0>; + label = "GIRQ_15"; + girq-id = <7>; + sources = <0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 19 20 22>; + status = "disabled"; + }; + girq16: girq16@a0 { + compatible = "microchip,xec-ecia-girq"; + reg = <0xa0 0x14>; + interrupts = <8 0>; + label = "GIRQ_16"; + girq-id = <8>; + sources = <0 2 3>; + status = "disabled"; + }; + girq17: girq17@b4 { + compatible = "microchip,xec-ecia-girq"; + reg = <0xb4 0x14>; + interrupts = <9 0>; + label = "GIRQ_17"; + girq-id = <9>; + sources = <0 1 2 3 4 8 9 10 11 12 13 14 15 + 16 17 20 21 22 23>; + status = "disabled"; + }; + girq18: girq18@c8 { + compatible = "microchip,xec-ecia-girq"; + reg = <0xc8 0x14>; + interrupts = <10 0>; + label = "GIRQ_18"; + girq-id = <10>; + sources = <0 1 2 3 4 5 6 7 + 10 20 21 22 23 + 24 25 26 27 28>; + status = "disabled"; + }; + girq19: girq19@dc { + compatible = "microchip,xec-ecia-girq"; + reg = <0xdc 0x14>; + interrupts = <11 0>; + label = "GIRQ_19"; + girq-id = <11>; + sources = <0 1 2 3 4 5 6 7 8 9 10>; + status = "disabled"; + }; + girq20: girq20@f0 { + compatible = "microchip,xec-ecia-girq"; + reg = <0xf0 0x14>; + interrupts = <12 0>; + label = "GIRQ_20"; + girq-id = <12>; + sources = <3 9>; + status = "disabled"; + }; + girq21: girq21@104 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x104 0x14>; + interrupts = <13 0>; + label = "GIRQ_21"; + girq-id = <13>; + sources = <2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 18 19 25 26>; + status = "disabled"; + }; + girq22: girq22@118 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x118 0x14>; + interrupts = <255 0>; + label = "GIRQ_22"; + girq-id = <14>; + sources = <0 1 2 3 4 5 9 15>; + status = "disabled"; + }; + girq23: girq23@12c { + compatible = "microchip,xec-ecia-girq"; + reg = <0x12c 0x14>; + interrupts = <14 0>; + label = "GIRQ_23"; + girq-id = <15>; + sources = <0 1 2 3 4 5 6 7 8 9 10 16 17>; + status = "disabled"; + }; + girq24: girq24@140 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x140 0x14>; + interrupts = <15 0>; + label = "GIRQ_24"; + girq-id = <16>; + sources = <0 1 2 3 4 5 6 7 8 9 10 11 + 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27>; + status = "disabled"; + }; + girq25: girq25@154 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x154 0x14>; + interrupts = <16 0>; + label = "GIRQ_25"; + girq-id = <17>; + sources = <0 1 2 3 4 5 6 7 8 9 10 11 + 12 13 14 15>; + status = "disabled"; + }; + girq26: girq26@168 { + compatible = "microchip,xec-ecia-girq"; + reg = <0x168 0x14>; + interrupts = <17 0>; + label = "GIRQ_26"; + girq-id = <18>; + sources = <0 1 2 3 4 5 6 12 13>; + status = "disabled"; + }; }; hibtimer0: timer@40009800 { reg = <0x40009800 0x20>; diff --git a/dts/bindings/interrupt-controller/microchip,xec-ecia-girq.yaml b/dts/bindings/interrupt-controller/microchip,xec-ecia-girq.yaml new file mode 100644 index 00000000000..387317638ed --- /dev/null +++ b/dts/bindings/interrupt-controller/microchip,xec-ecia-girq.yaml @@ -0,0 +1,26 @@ +description: Microchip XEC series External Interrupt Aggregator GIRQ + +compatible: "microchip,xec-ecia-girq" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + label: + required: true + + girq-id: + type: int + required: true + description: GIRQ ID number [0, 18] + + sources: + type: array + required: true + description: | + Bit positions of each source implemented by this GIRQ. diff --git a/dts/bindings/interrupt-controller/microchip,xec-ecia.yaml b/dts/bindings/interrupt-controller/microchip,xec-ecia.yaml new file mode 100644 index 00000000000..c033f99b546 --- /dev/null +++ b/dts/bindings/interrupt-controller/microchip,xec-ecia.yaml @@ -0,0 +1,22 @@ +description: Microchip XEC series External Interrupt Aggregator Controller + +compatible: "microchip,xec-ecia" + +include: base.yaml + +properties: + reg: + required: true + + label: + required: true + + clocks: + required: true + + direct-capable-girqs: + type: array + required: true + description: | + Array of GIRQ numbers in [8, 26] whose result bits can be connected + directly to the ARM NVIC. diff --git a/include/drivers/interrupt_controller/intc_mchp_xec_ecia.h b/include/drivers/interrupt_controller/intc_mchp_xec_ecia.h new file mode 100644 index 00000000000..e5093004a59 --- /dev/null +++ b/include/drivers/interrupt_controller/intc_mchp_xec_ecia.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2021 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Driver for External interrupt controller in Microchip XEC devices + * + * Based on reference manuals: + * Reference Manuals for MEC152x and MEC172x ARM(r) 32-bit MCUs + * + * Chapter: EC Interrupt Aggregator (ECIA) + * + */ + +#ifndef ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_MCHP_XEC_ECIA_H_ +#define ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_MCHP_XEC_ECIA_H_ + +#include +#include + +/** + * @brief enable GIRQn interrupt for specific source + * + * @param girq_id is the GIRQ number (8 - 26) + * @param src is the interrupt source in the GIRQ (0 - 31) + */ +int mchp_xec_ecia_enable(int girq_id, int src); + +/** + * @brief disable EXTI interrupt for specific line + * + * @param girq_id is the GIRQ number (8 - 26) + * @param src is the interrupt source in the GIRQ (0 - 31) + */ +int mchp_xec_ecia_disable(int girq_id, int src); + + +/* callback for ECIA GIRQ interrupt source */ +typedef void (*mchp_xec_ecia_callback_t) (int girq_id, int src, void *user); + +/** + * @brief set GIRQn interrupt source callback + * + * @param girq_id is the GIRQ number (8 - 26) + * @param src is the interrupt source in the GIRQ (0 - 31) + * @param cb user callback + * @param data user data + */ +int mchp_xec_ecia_set_callback(int girq_id, int src, + mchp_xec_ecia_callback_t cb, void *data); + +/** + * @brief set GIRQn interrupt source callback + * + * @param dev_girq is a handle to the GIRQn device + * @param src is the interrupt source in the GIRQ (0 - 31) + * @param cb user callback + * @param data user data + */ +int mchp_xec_ecia_set_callback_by_dev(const struct device *dev_girq, int src, + mchp_xec_ecia_callback_t cb, void *data); + +/** + * @brief unset GIRQn interrupt source callback + * + * @param girq_id is the GIRQ number (8 - 26) + * @param src is the interrupt source in the GIRQ (0 - 31) + */ +int mchp_ecia_unset_callback(int girq_id, int src); + +/** + * @brief unset GIRQn interrupt source callback + * + * @param dev_girq is a handle to the GIRQn device + * @param src is the interrupt source in the GIRQ (0 - 31) + */ +int mchp_ecia_unset_callback_by_dev(const struct device *dev_girq, int src); + +/* platform specific */ +/** @brief enable or disable aggregated GIRQ output + * + * @param girq_id is the GIRQ number (8 - 26) + * @param enable non-zero enables aggregated output else disables + */ +void mchp_xec_ecia_girq_aggr_en(uint8_t girq_id, uint8_t enable); + +/** @brief clear GIRQ latched source status bit + * + * @param girq_id is the GIRQ number (8 - 26) + * @param src_bit is the source bit position in the GIRQ registers (0 - 31) + */ +void mchp_xec_ecia_girq_src_clr(uint8_t girq_id, uint8_t src_bit); + +/** @brief enable a source in a GIRQ + * + * @param girq_id is the GIRQ number (8 - 26) + * @param src_bit is the source bit position in the GIRQ registers (0 - 31) + */ +void mchp_xec_ecia_girq_src_en(uint8_t girq_id, uint8_t src_bit); + +/** @brief disable a source in a GIRQ + * + * @param girq_id is the GIRQ number (8 - 26) + * @param src_bit is the source bit position in the GIRQ registers (0 - 31) + */ +void mchp_xec_ecia_girq_src_dis(uint8_t girq_id, uint8_t src_bit); + +/** @brief clear GIRQ latches sources specified in bitmap + * + * @param girq_id is the GIRQ number (8 - 26) + * @param bitmap contains the source bits to clear + */ +void mchp_xec_ecia_girq_src_clr_bitmap(uint8_t girq_id, uint32_t bitmap); + +/** @brief enable sources in a GIRQ + * + * @param girq_id is the GIRQ number (8 - 26) + * @param bitmap contains the source bits to enable + */ +void mchp_xec_ecia_girq_src_en_bitmap(uint8_t girq_id, uint32_t bitmap); + +/** @brief disable sources in a GIRQ + * + * @param girq_id is the GIRQ number (8 - 26) + * @param bitmap contains the source bits to disable + */ +void mchp_xec_ecia_girq_src_dis_bitmap(uint8_t girq_id, uint32_t bitmap); + +/** @brief Read GIRQ result register (bit-wise OR of enable and source) + * + * @param girq_id is the GIRQ number (8 - 26) + * @return 32-bit unsigned result register value + */ +uint32_t mchp_xec_ecia_girq_result(uint8_t girq_id); + +/** @brief Clear external NVIC input pending status + * + * @param nvic_num is 0 to maximum NVIC inputs for the chip. + */ +void mchp_xec_ecia_nvic_clr_pend(uint32_t nvic_num); + +#endif /* ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_MCHP_XEC_ECIA_H_ */ diff --git a/include/dt-bindings/interrupt-controller/mchp-xec-ecia.h b/include/dt-bindings/interrupt-controller/mchp-xec-ecia.h new file mode 100644 index 00000000000..149625d7e4c --- /dev/null +++ b/include/dt-bindings/interrupt-controller/mchp-xec-ecia.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2021 Microchip Technology + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __DT_BINDING_MCHP_XEC_ECIA_H +#define __DT_BINDING_MCHP_XEC_ECIA_H + +#define MCHP_ECIA_DIRECT_BITMAP 0x00bfe000 + +#endif /* __DT_BINDING_MCHP_XEC_ECIA_H */ diff --git a/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series b/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series index c783649418f..76244dde6a9 100644 --- a/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series +++ b/soc/arm/microchip_mec/mec172x/Kconfig.defconfig.series @@ -22,4 +22,9 @@ config CORTEX_M_SYSTICK config CLOCK_CONTROL_MCHP_XEC default y +config MCHP_ECIA_XEC + default y + help + Enable support for Microchip XEC ECIA driver + endif # SOC_SERIES_MEC172X