ITE drivers/interrupt_controller: add intc_ite_it8xxx2_v2 driver
This driver is made for it82xx2 series. Signed-off-by: Ruibin Chang <Ruibin.Chang@ite.com.tw>
This commit is contained in:
parent
44250a9e67
commit
b9a7340ded
|
@ -15,6 +15,7 @@ zephyr_library_sources_ifdef(CONFIG_GIC_V3_ITS intc_gicv3_its.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_INTEL_VTD_ICTL intc_intel_vtd.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_IOAPIC intc_ioapic.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ITE_IT8XXX2_INTC intc_ite_it8xxx2.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ITE_IT8XXX2_INTC_V2 intc_ite_it8xxx2_v2.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ITE_IT8XXX2_WUC wuc_ite_it8xxx2.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_LEON_IRQMP intc_irqmp.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_LOAPIC intc_loapic.c intc_system_apic.c)
|
||||
|
|
|
@ -1,15 +1,29 @@
|
|||
# Copyright (c) 2015 ITE Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config HAS_ITE_INTC
|
||||
bool
|
||||
help
|
||||
This option is selected when ITE_IT8XXX2_INTC or
|
||||
ITE_IT8XXX2_INTC_V2 is enabled.
|
||||
|
||||
config ITE_IT8XXX2_INTC
|
||||
def_bool DT_HAS_ITE_IT8XXX2_INTC_ENABLED
|
||||
depends on DT_HAS_ITE_IT8XXX2_INTC_ENABLED
|
||||
select HAS_ITE_INTC
|
||||
help
|
||||
Configures the maximum number of clients allowed per shared
|
||||
instance of the shared interrupt driver. To conserve RAM set
|
||||
this value to the lowest practical value.
|
||||
this software interrupt default set on by device tree.
|
||||
|
||||
config ITE_IT8XXX2_INTC_V2
|
||||
def_bool DT_HAS_ITE_IT8XXX2_INTC_V2_ENABLED
|
||||
depends on DT_HAS_ITE_IT8XXX2_INTC_V2_ENABLED
|
||||
select HAS_ITE_INTC
|
||||
help
|
||||
This option enables the interrupt controller for IT82XX2 family.
|
||||
|
||||
config ITE_IT8XXX2_WUC
|
||||
bool "ITE it8xxx2 Wakeup controller (WUC) interface"
|
||||
default y
|
||||
|
|
|
@ -241,7 +241,7 @@ uint8_t __soc_ram_code get_irq(void *arg)
|
|||
return intc_irq;
|
||||
}
|
||||
|
||||
void ite_intc_init(void)
|
||||
void soc_interrupt_init(void)
|
||||
{
|
||||
/* Ensure interrupts of soc are disabled at default */
|
||||
for (int i = 0; i < ARRAY_SIZE(reg_enable); i++)
|
||||
|
|
242
drivers/interrupt_controller/intc_ite_it8xxx2_v2.c
Normal file
242
drivers/interrupt_controller/intc_ite_it8xxx2_v2.c
Normal file
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* Copyright (c) 2023 ITE Corporation. All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/arch/cpu.h>
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/printk.h>
|
||||
#include <zephyr/sw_isr_table.h>
|
||||
#include "intc_ite_it8xxx2.h"
|
||||
LOG_MODULE_REGISTER(intc_it8xxx2_v2, LOG_LEVEL_DBG);
|
||||
|
||||
#define IT8XXX2_INTC_BASE DT_REG_ADDR(DT_NODELABEL(intc))
|
||||
#define IT8XXX2_INTC_BASE_SHIFT(g) (IT8XXX2_INTC_BASE + ((g) << 2))
|
||||
|
||||
/* Interrupt status register */
|
||||
#define IT8XXX2_INTC_ISR(g) ECREG(IT8XXX2_INTC_BASE_SHIFT(g) + \
|
||||
((g) < 4 ? 0x0 : 0x4))
|
||||
/* Interrupt enable register */
|
||||
#define IT8XXX2_INTC_IER(g) ECREG(IT8XXX2_INTC_BASE_SHIFT(g) + \
|
||||
((g) < 4 ? 0x1 : 0x5))
|
||||
/* Interrupt edge/level triggered mode register */
|
||||
#define IT8XXX2_INTC_IELMR(g) ECREG(IT8XXX2_INTC_BASE_SHIFT(g) + \
|
||||
((g) < 4 ? 0x2 : 0x6))
|
||||
/* Interrupt polarity register */
|
||||
#define IT8XXX2_INTC_IPOLR(g) ECREG(IT8XXX2_INTC_BASE_SHIFT(g) + \
|
||||
((g) < 4 ? 0x3 : 0x7))
|
||||
|
||||
#define IT8XXX2_INTC_GROUP_CNT 24
|
||||
#define MAX_REGISR_IRQ_NUM 8
|
||||
#define IVECT_OFFSET_WITH_IRQ 0x10
|
||||
|
||||
/* Interrupt number of INTC module */
|
||||
static uint8_t intc_irq;
|
||||
static uint8_t ier_setting[IT8XXX2_INTC_GROUP_CNT];
|
||||
|
||||
void ite_intc_save_and_disable_interrupts(void)
|
||||
{
|
||||
/* Disable global interrupt for critical section */
|
||||
unsigned int key = irq_lock();
|
||||
|
||||
/* Save and disable interrupts */
|
||||
for (int i = 0; i < IT8XXX2_INTC_GROUP_CNT; i++) {
|
||||
ier_setting[i] = IT8XXX2_INTC_IER(i);
|
||||
IT8XXX2_INTC_IER(i) = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This load operation will guarantee the above modification of
|
||||
* SOC's register can be seen by any following instructions.
|
||||
* Note: Barrier instruction can not synchronize chip register,
|
||||
* so we introduce workaround here.
|
||||
*/
|
||||
IT8XXX2_INTC_IER(IT8XXX2_INTC_GROUP_CNT - 1);
|
||||
|
||||
irq_unlock(key);
|
||||
}
|
||||
|
||||
void ite_intc_restore_interrupts(void)
|
||||
{
|
||||
/*
|
||||
* Ensure the highest priority interrupt will be the first fired
|
||||
* interrupt when soc is ready to go.
|
||||
*/
|
||||
unsigned int key = irq_lock();
|
||||
|
||||
/* Restore interrupt state */
|
||||
for (int i = 0; i < IT8XXX2_INTC_GROUP_CNT; i++) {
|
||||
IT8XXX2_INTC_IER(i) = ier_setting[i];
|
||||
}
|
||||
|
||||
irq_unlock(key);
|
||||
}
|
||||
|
||||
void ite_intc_isr_clear(unsigned int irq)
|
||||
{
|
||||
uint32_t group, index;
|
||||
|
||||
if (irq > CONFIG_NUM_IRQS) {
|
||||
return;
|
||||
}
|
||||
|
||||
group = irq / MAX_REGISR_IRQ_NUM;
|
||||
index = irq % MAX_REGISR_IRQ_NUM;
|
||||
|
||||
IT8XXX2_INTC_ISR(group) = BIT(index);
|
||||
}
|
||||
|
||||
void __soc_ram_code ite_intc_irq_enable(unsigned int irq)
|
||||
{
|
||||
uint32_t group, index;
|
||||
|
||||
if (irq > CONFIG_NUM_IRQS) {
|
||||
return;
|
||||
}
|
||||
|
||||
group = irq / MAX_REGISR_IRQ_NUM;
|
||||
index = irq % MAX_REGISR_IRQ_NUM;
|
||||
|
||||
/* Critical section due to run a bit-wise OR operation */
|
||||
unsigned int key = irq_lock();
|
||||
|
||||
IT8XXX2_INTC_IER(group) |= BIT(index);
|
||||
|
||||
irq_unlock(key);
|
||||
}
|
||||
|
||||
void __soc_ram_code ite_intc_irq_disable(unsigned int irq)
|
||||
{
|
||||
uint32_t group, index;
|
||||
|
||||
if (irq > CONFIG_NUM_IRQS) {
|
||||
return;
|
||||
}
|
||||
|
||||
group = irq / MAX_REGISR_IRQ_NUM;
|
||||
index = irq % MAX_REGISR_IRQ_NUM;
|
||||
|
||||
/* Critical section due to run a bit-wise NAND operation */
|
||||
unsigned int key = irq_lock();
|
||||
|
||||
IT8XXX2_INTC_IER(group) &= ~BIT(index);
|
||||
/*
|
||||
* This load operation will guarantee the above modification of
|
||||
* SOC's register can be seen by any following instructions.
|
||||
*/
|
||||
IT8XXX2_INTC_IER(group);
|
||||
|
||||
irq_unlock(key);
|
||||
}
|
||||
|
||||
void ite_intc_irq_polarity_set(unsigned int irq, unsigned int flags)
|
||||
{
|
||||
uint32_t group, index;
|
||||
|
||||
if (irq > CONFIG_NUM_IRQS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((flags & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
|
||||
return;
|
||||
}
|
||||
|
||||
group = irq / MAX_REGISR_IRQ_NUM;
|
||||
index = irq % MAX_REGISR_IRQ_NUM;
|
||||
|
||||
if ((flags & IRQ_TYPE_LEVEL_HIGH) || (flags & IRQ_TYPE_EDGE_RISING)) {
|
||||
IT8XXX2_INTC_IPOLR(group) &= ~BIT(index);
|
||||
} else {
|
||||
IT8XXX2_INTC_IPOLR(group) |= BIT(index);
|
||||
}
|
||||
|
||||
if ((flags & IRQ_TYPE_LEVEL_LOW) || (flags & IRQ_TYPE_LEVEL_HIGH)) {
|
||||
IT8XXX2_INTC_IELMR(group) &= ~BIT(index);
|
||||
} else {
|
||||
IT8XXX2_INTC_IELMR(group) |= BIT(index);
|
||||
}
|
||||
}
|
||||
|
||||
int __soc_ram_code ite_intc_irq_is_enable(unsigned int irq)
|
||||
{
|
||||
uint32_t group, index;
|
||||
|
||||
if (irq > CONFIG_NUM_IRQS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
group = irq / MAX_REGISR_IRQ_NUM;
|
||||
index = irq % MAX_REGISR_IRQ_NUM;
|
||||
|
||||
return IS_MASK_SET(IT8XXX2_INTC_IER(group), BIT(index));
|
||||
}
|
||||
|
||||
uint8_t __soc_ram_code ite_intc_get_irq_num(void)
|
||||
{
|
||||
return intc_irq;
|
||||
}
|
||||
|
||||
bool __soc_ram_code ite_intc_no_irq(void)
|
||||
{
|
||||
return (IVECT == IVECT_OFFSET_WITH_IRQ);
|
||||
}
|
||||
|
||||
uint8_t __soc_ram_code get_irq(void *arg)
|
||||
{
|
||||
ARG_UNUSED(arg);
|
||||
|
||||
/* Wait until two equal interrupt values are read */
|
||||
do {
|
||||
/* Read interrupt number from interrupt vector register */
|
||||
intc_irq = IVECT;
|
||||
/*
|
||||
* WORKAROUND: when the interrupt vector register (IVECT)
|
||||
* isn't latched in a load operation, we read it again to make
|
||||
* sure the value we got is the correct value.
|
||||
*/
|
||||
} while (intc_irq != IVECT);
|
||||
|
||||
/* Determine interrupt number */
|
||||
intc_irq -= IVECT_OFFSET_WITH_IRQ;
|
||||
|
||||
/*
|
||||
* Look for pending interrupt if there's interrupt number 0 from
|
||||
* the AIVECT register.
|
||||
*/
|
||||
if (intc_irq == 0) {
|
||||
uint8_t int_pending;
|
||||
|
||||
for (int i = (IT8XXX2_INTC_GROUP_CNT - 1); i >= 0; i--) {
|
||||
int_pending =
|
||||
(IT8XXX2_INTC_ISR(i) & IT8XXX2_INTC_IER(i));
|
||||
if (int_pending != 0) {
|
||||
intc_irq = (MAX_REGISR_IRQ_NUM * i) +
|
||||
find_msb_set(int_pending) - 1;
|
||||
LOG_DBG("Pending interrupt found: %d",
|
||||
intc_irq);
|
||||
LOG_DBG("CPU mepc: 0x%lx", csr_read(mepc));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear interrupt status */
|
||||
ite_intc_isr_clear(intc_irq);
|
||||
|
||||
/* Return interrupt number */
|
||||
return intc_irq;
|
||||
}
|
||||
|
||||
void soc_interrupt_init(void)
|
||||
{
|
||||
/* Ensure interrupts of soc are disabled at default */
|
||||
for (int i = 0; i < IT8XXX2_INTC_GROUP_CNT; i++) {
|
||||
IT8XXX2_INTC_IER(i) = 0;
|
||||
}
|
||||
|
||||
/* Enable M-mode external interrupt */
|
||||
csr_set(mie, MIP_MEIP);
|
||||
}
|
15
dts/bindings/interrupt-controller/ite,it8xxx2-intc-v2.yaml
Normal file
15
dts/bindings/interrupt-controller/ite,it8xxx2-intc-v2.yaml
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Copyright (c) 2023 ITE Corporation. All Rights Reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: ITE Interrupt controller
|
||||
compatible: "ite,it8xxx2-intc-v2"
|
||||
|
||||
include: [interrupt-controller.yaml, base.yaml]
|
||||
|
||||
properties:
|
||||
reg:
|
||||
required: true
|
||||
|
||||
interrupt-cells:
|
||||
- irq
|
||||
- flags
|
20
dts/riscv/ite/it82xx2.dtsi
Normal file
20
dts/riscv/ite/it82xx2.dtsi
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (c) 2023 ITE Corporation. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <ite/it8xxx2.dtsi>
|
||||
|
||||
/ {
|
||||
soc {
|
||||
intc: interrupt-controller@f03f00 {
|
||||
compatible = "ite,it8xxx2-intc-v2";
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-controller;
|
||||
reg = <0x00f03f00 0x0100>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
#ifndef _ASMLANGUAGE
|
||||
|
||||
#if CONFIG_ITE_IT8XXX2_INTC
|
||||
#ifdef CONFIG_HAS_ITE_INTC
|
||||
/*
|
||||
* Save current interrupt state of soc-level into ier_setting[] with
|
||||
* disabling interrupt.
|
||||
|
@ -44,7 +44,7 @@ extern void ite_intc_irq_polarity_set(unsigned int irq, unsigned int flags);
|
|||
extern void ite_intc_isr_clear(unsigned int irq);
|
||||
void ite_intc_init(void);
|
||||
bool ite_intc_no_irq(void);
|
||||
#endif /* CONFIG_ITE_IT8XXX2_INTC */
|
||||
#endif /* CONFIG_HAS_ITE_INTC */
|
||||
|
||||
#ifdef CONFIG_SOC_IT8XXX2_PLL_FLASH_48M
|
||||
void timer_5ms_one_shot(void);
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
|
||||
void arch_irq_enable(unsigned int irq)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ITE_IT8XXX2_INTC)) {
|
||||
if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) {
|
||||
ite_intc_irq_enable(irq);
|
||||
}
|
||||
}
|
||||
|
||||
void arch_irq_disable(unsigned int irq)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ITE_IT8XXX2_INTC)) {
|
||||
if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) {
|
||||
ite_intc_irq_disable(irq);
|
||||
}
|
||||
};
|
||||
|
@ -31,7 +31,7 @@ int arch_irq_is_enabled(unsigned int irq)
|
|||
* Return true from arch_irq_is_enabled() when external interrupt-enable
|
||||
* bit, and SOC's IER are both true.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_ITE_IT8XXX2_INTC)) {
|
||||
if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) {
|
||||
return ((csr_read(mie) & BIT(IRQ_M_EXT)) &&
|
||||
ite_intc_irq_is_enable(irq));
|
||||
} else {
|
||||
|
|
|
@ -6,13 +6,6 @@ if SOC_SERIES_RISCV32_IT8XXX2
|
|||
config SOC_SERIES
|
||||
default "it8xxx2"
|
||||
|
||||
config ITE_IT8XXX2_INTC
|
||||
default y
|
||||
select FLASH
|
||||
select FLASH_HAS_PAGE_LAYOUT
|
||||
select FLASH_HAS_DRIVER_ENABLED
|
||||
select HAS_FLASH_LOAD_OFFSET
|
||||
|
||||
config RISCV_GP
|
||||
default y
|
||||
|
||||
|
@ -46,7 +39,6 @@ config VCMP_IT8XXX2_INIT_PRIORITY
|
|||
config PINCTRL
|
||||
default y
|
||||
|
||||
if ITE_IT8XXX2_INTC
|
||||
config NUM_IRQS
|
||||
default 185
|
||||
|
||||
|
@ -65,8 +57,6 @@ config GEN_SW_ISR_TABLE
|
|||
config RISCV_SOC_INTERRUPT_INIT
|
||||
default y
|
||||
|
||||
endif # ITE_IT8XXX2_INTC
|
||||
|
||||
source "soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it8*"
|
||||
|
||||
endif # SOC_SERIES_RISCV32_IT8XXX2
|
||||
|
|
|
@ -17,6 +17,10 @@ config SOC_IT8XXX2
|
|||
select RISCV_ISA_EXT_M if !(SOC_IT81302_BX || SOC_IT81202_BX)
|
||||
select RISCV_ISA_EXT_A
|
||||
select RISCV_ISA_EXT_C
|
||||
select FLASH
|
||||
select FLASH_HAS_PAGE_LAYOUT
|
||||
select FLASH_HAS_DRIVER_ENABLED
|
||||
select HAS_FLASH_LOAD_OFFSET
|
||||
|
||||
endchoice
|
||||
|
||||
|
|
|
@ -159,12 +159,12 @@ static void chip_configure_pll(const struct pll_config_t *pll)
|
|||
static int chip_change_pll(void)
|
||||
{
|
||||
|
||||
if (IS_ENABLED(CONFIG_ITE_IT8XXX2_INTC)) {
|
||||
if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) {
|
||||
ite_intc_save_and_disable_interrupts();
|
||||
}
|
||||
/* configure PLL/CPU/flash clock */
|
||||
chip_configure_pll(&pll_configuration[0]);
|
||||
if (IS_ENABLED(CONFIG_ITE_IT8XXX2_INTC)) {
|
||||
if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) {
|
||||
ite_intc_restore_interrupts();
|
||||
}
|
||||
|
||||
|
@ -267,11 +267,6 @@ void arch_cpu_atomic_idle(unsigned int key)
|
|||
riscv_idle(CHIP_PLL_DOZE, key);
|
||||
}
|
||||
|
||||
void soc_interrupt_init(void)
|
||||
{
|
||||
ite_intc_init();
|
||||
}
|
||||
|
||||
static int ite_it8xxx2_init(void)
|
||||
{
|
||||
struct gpio_it8xxx2_regs *const gpio_regs = GPIO_IT8XXX2_REG_BASE;
|
||||
|
|
Loading…
Reference in a new issue