Microchip: MEC172x Add aggregated interrupt driver

Add driver implementation and header files for a MEC172x
aggregated interrupt driver. Enable the parent(ECIA) node
to have the driver initialize interrupt hardware for use.
Enable child nodes for those GIRQs used for aggregation.
Refer to chip documention for the list of GIRQs restricted
to aggregation and those which support direct mode.
Add chip level device tree node for MEC172x EC interrupt
aggregator parent and GIRQ children. Each child node contains
a list of sources representing the source bit position in the
GIRQ registers.
Add DT bindings for ECIA and GIRQ nodes.
Add build file(s) and configuration items for the MEC172x ECIA
aggregated interrupt driver. Add and enable the MEC172x interrupt
driver on the MEC172x evaluation board(EVB). Enable parent node to
initialize ECIA hardware. Child nodes are left disabled until a
future driver needs them.

Signed-off-by: Scott Worley <scott.worley@microchip.com>
This commit is contained in:
Scott Worley 2021-07-21 14:12:52 -04:00 committed by Christopher Friedt
commit 6b3749d2ff
11 changed files with 948 additions and 3 deletions

View file

@ -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>;
};

View file

@ -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)

View file

@ -70,4 +70,6 @@ source "drivers/interrupt_controller/Kconfig.intel_vtd"
source "drivers/interrupt_controller/Kconfig.esp32"
source "drivers/interrupt_controller/Kconfig.xec"
endmenu

View file

@ -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

View file

@ -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 <arch/cpu.h>
#include <arch/arm/aarch32/cortex_m/cmsis.h>
#include <device.h>
#include <soc.h>
#include <sys/__assert.h>
#include <drivers/clock_control/mchp_xec_clock_control.h>
#include <drivers/interrupt_controller/intc_mchp_xec_ecia.h>
/* 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];
}

View file

@ -9,6 +9,7 @@
#include <dt-bindings/i2c/i2c.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/clock/mchp_xec_pcr.h>
#include <dt-bindings/interrupt-controller/mchp-xec-ecia.h>
/ {
cpus {
@ -47,9 +48,213 @@
periph-32k-src = <MCHP_XEC_CLK32K_SRC_SIL_OSC>;
#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>;

View file

@ -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.

View file

@ -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.

View file

@ -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 <device.h>
#include <irq.h>
/**
* @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_ */

View file

@ -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 */

View file

@ -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