From 97aa90570c039edeeb21b61903c1755e0fec22bf Mon Sep 17 00:00:00 2001 From: Tiago Medicci Serrano Date: Fri, 24 Jan 2025 12:53:45 -0300 Subject: [PATCH 01/33] xtensa/esp32s3: allow moving .bss data to the external PSRAM This commit allows placing .bss data into the external PSRAM. Previously, the PSRAM was fully allocated to the heap memory only and now part of it can be used to allocate .bss data freeing the internal memory. --- arch/xtensa/src/esp32s3/esp32s3_spiram.c | 12 +- .../common/scripts/esp32s3_sections.ld | 129 ++++++++++-------- .../esp32s3/common/scripts/flat_memory.ld | 11 ++ 3 files changed, 95 insertions(+), 57 deletions(-) diff --git a/arch/xtensa/src/esp32s3/esp32s3_spiram.c b/arch/xtensa/src/esp32s3/esp32s3_spiram.c index d8b6259610db3..aba0956b002e1 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_spiram.c +++ b/arch/xtensa/src/esp32s3/esp32s3_spiram.c @@ -122,6 +122,9 @@ static struct smp_call_data_s g_call_data = SMP_CALL_INITIALIZER(pause_cpu_handler, NULL); #endif +extern uint8_t _ext_ram_bss_start; +extern uint8_t _ext_ram_bss_end; + /**************************************************************************** * ROM Function Prototypes ****************************************************************************/ @@ -393,6 +396,7 @@ int IRAM_ATTR esp_spiram_init_cache(void) uint32_t mapped_vaddr_size; uint32_t target_mapped_vaddr_start; uint32_t target_mapped_vaddr_end; + uint32_t ext_bss_size; int ret = psram_get_available_size(&psram_size); if (ret != OK) @@ -473,10 +477,12 @@ int IRAM_ATTR esp_spiram_init_cache(void) cache_resume_dcache(0); - /* Currently no non-heap stuff on ESP32S3 */ + ext_bss_size = ((intptr_t)&_ext_ram_bss_end - + (intptr_t)&_ext_ram_bss_start); - g_allocable_vaddr_start = g_mapped_vaddr_start; - g_allocable_vaddr_end = g_mapped_vaddr_start + g_mapped_size; + g_allocable_vaddr_start = g_mapped_vaddr_start + ext_bss_size; + g_allocable_vaddr_end = g_mapped_vaddr_start + g_mapped_size - + ext_bss_size; return ret; } diff --git a/boards/xtensa/esp32s3/common/scripts/esp32s3_sections.ld b/boards/xtensa/esp32s3/common/scripts/esp32s3_sections.ld index b0d5edd15ca65..ce35fcf5a391b 100644 --- a/boards/xtensa/esp32s3/common/scripts/esp32s3_sections.ld +++ b/boards/xtensa/esp32s3/common/scripts/esp32s3_sections.ld @@ -438,11 +438,7 @@ SECTIONS _sheap = ABSOLUTE(.); } >dram0_0_seg AT>ROM - _image_drom_vma = ADDR(.flash.rodata); - _image_drom_lma = LOADADDR(.flash.rodata); - _image_drom_size = LOADADDR(.flash.rodata) + SIZEOF(.flash.rodata) - _image_drom_lma; - - /* The alignment of the ".flash.rodata" output section is forced to + /* The alignment of the ".flash.text" output section is forced to * 0x00010000 (64KB) to ensure that it will be allocated at the beginning * of the next available Flash block. * This is required to meet the following constraint from the external @@ -453,10 +449,64 @@ SECTIONS * be equal. */ + .flash.text : ALIGN(0x00010000) + { + _stext = .; + _instruction_reserved_start = ABSOLUTE(.); + + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */ + *(.fini.literal) + *(.fini) + *(.gnu.version) + + *(EXCLUDE_FILE(*libnet80211.a *libpp.a) .wifi0iram EXCLUDE_FILE(*libnet80211.a *libpp.a) .wifi0iram.*) + *(.wifiextrairam .wifiextrairam.*) + *(EXCLUDE_FILE(*libpp.a) .wifiorslpiram EXCLUDE_FILE(*libpp.a) .wifiorslpiram.*) + *(EXCLUDE_FILE(*libnet80211.a *libpp.a) .wifirxiram EXCLUDE_FILE(*libnet80211.a *libpp.a) .wifirxiram.*) + *(.wifislpiram .wifislpiram.*) + *(EXCLUDE_FILE(*libnet80211.a *libpp.a) .wifislprxiram EXCLUDE_FILE(*libnet80211.a *libpp.a) .wifislprxiram.*) + + /* CPU will try to prefetch up to 16 bytes of instructions. + * This means that any configuration (e.g. MMU, PMS) must allow + * safe access to up to 16 bytes after the last real instruction, add + * dummy bytes to ensure this + */ + + . += 16; + + _instruction_reserved_end = ABSOLUTE(.); + _etext = .; + } >irom0_0_seg AT>ROM + + _image_irom_vma = ADDR(.flash.text); + _image_irom_lma = LOADADDR(.flash.text); + _image_irom_size = LOADADDR(.flash.text) + SIZEOF(.flash.text) - _image_irom_lma; + + /* Dummy section represents the .flash.text section but in drom0_0_seg. + * Thus, it must have its alignment and (at least) its size. + */ + .flash.rodata_dummy (NOLOAD) : { - . = ALIGN(0x10000); - } > ROM + _flash_rodata_dummy_start = ABSOLUTE(.); + . = ALIGN(ALIGNOF(.flash.text)) + SIZEOF(.flash.text); + + /* Add alignment of MMU page size + 0x20 bytes for the mapping header. */ + + . = ALIGN(0x10000) + 0x20; + } > drom0_0_seg + + /* The alignment of the ".flash.rodata" output section is forced to + * 0x00010000 (64KB) to ensure that it will be allocated at the beginning + * of the next available Flash block. + * This is required to meet the following constraint from the external + * flash MMU: + * VMA % 64KB == LMA % 64KB + * i.e. the lower 16 bits of both the virtual address (address seen by the + * CPU) and the load address (physical address of the external flash) must + * be equal. + */ .flash.rodata : ALIGN(0x10000) { @@ -544,62 +594,33 @@ SECTIONS } >drom0_0_seg AT>ROM _rodata_reserved_align = ALIGNOF(.flash.rodata); - _image_irom_vma = ADDR(.flash.text); - _image_irom_lma = LOADADDR(.flash.text); - _image_irom_size = LOADADDR(.flash.text) + SIZEOF(.flash.text) - _image_irom_lma; + _image_drom_vma = ADDR(.flash.rodata); + _image_drom_lma = LOADADDR(.flash.rodata); + _image_drom_size = LOADADDR(.flash.rodata) + SIZEOF(.flash.rodata) - _image_drom_lma; - /* The alignment of the ".flash.text" output section is forced to - * 0x00010000 (64KB) to ensure that it will be allocated at the beginning - * of the next available Flash block. - * This is required to meet the following constraint from the external - * flash MMU: - * VMA % 64KB == LMA % 64KB - * i.e. the lower 16 bits of both the virtual address (address seen by the - * CPU) and the load address (physical address of the external flash) must - * be equal. + /* Dummy section to skip flash rodata sections. + * Because to `extern_ram_seg` and `drom0_0_seg` are on the same bus */ -#ifndef CONFIG_ESP32S3_RUN_IRAM - .flash.text_dummy (NOLOAD) : ALIGN(0x10000) + .ext_ram.dummy (NOLOAD): { - /* This section is required to skip .flash.rodata area because irom0_0_seg - * and drom0_0_seg reflect the same address space on different buses. - */ + . = ORIGIN(extern_ram_seg); + . = . + (_rodata_reserved_end - _flash_rodata_dummy_start); + . = ALIGN (0x10000); + } > extern_ram_seg - . += _image_drom_lma; - . += _image_drom_size; - } >irom0_0_seg -#endif + /* This section holds .ext_ram.bss data, and will be put in PSRAM */ - .flash.text : ALIGN(0x00010000) + .ext_ram.bss (NOLOAD) : { - _stext = .; - _instruction_reserved_start = ABSOLUTE(.); + _ext_ram_bss_start = ABSOLUTE(.); - *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) - *(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */ - *(.fini.literal) - *(.fini) - *(.gnu.version) - - *(EXCLUDE_FILE(*libnet80211.a *libpp.a) .wifi0iram EXCLUDE_FILE(*libnet80211.a *libpp.a) .wifi0iram.*) - *(.wifiextrairam .wifiextrairam.*) - *(EXCLUDE_FILE(*libpp.a) .wifiorslpiram EXCLUDE_FILE(*libpp.a) .wifiorslpiram.*) - *(EXCLUDE_FILE(*libnet80211.a *libpp.a) .wifirxiram EXCLUDE_FILE(*libnet80211.a *libpp.a) .wifirxiram.*) - *(.wifislpiram .wifislpiram.*) - *(EXCLUDE_FILE(*libnet80211.a *libpp.a) .wifislprxiram EXCLUDE_FILE(*libnet80211.a *libpp.a) .wifislprxiram.*) + *(.ext_ram.bss .ext_ram.bss.*) + *libpython3.13.a:(*.PyRuntime) - /* CPU will try to prefetch up to 16 bytes of instructions. - * This means that any configuration (e.g. MMU, PMS) must allow - * safe access to up to 16 bytes after the last real instruction, add - * dummy bytes to ensure this - */ - - . += 16; - - _instruction_reserved_end = ABSOLUTE(.); - _etext = .; - } >irom0_0_seg AT>ROM + . = ALIGN(4); + _ext_ram_bss_end = ABSOLUTE(.); + } > extern_ram_seg .rtc.text : { diff --git a/boards/xtensa/esp32s3/common/scripts/flat_memory.ld b/boards/xtensa/esp32s3/common/scripts/flat_memory.ld index ee0e928855fd7..4afdfcb2eb347 100644 --- a/boards/xtensa/esp32s3/common/scripts/flat_memory.ld +++ b/boards/xtensa/esp32s3/common/scripts/flat_memory.ld @@ -184,6 +184,17 @@ MEMORY rtc_slow_seg(RW) : org = 0x50000000 + CONFIG_ESP32S3_ULP_COPROC_RESERVE_MEM, len = 0x2000 - CONFIG_ESP32S3_ULP_COPROC_RESERVE_MEM + + /* `extern_ram_seg` and `drom0_0_seg` share the same bus and the address region. + * A dummy section is used to avoid overlap. See `.ext_ram.dummy` in `esp32s3_sections.ld + */ + +#ifdef CONFIG_ESP32S3_APP_FORMAT_MCUBOOT + extern_ram_seg(RWX) : org = 0x3c000000 + ORIGIN(ROM), + len = 0x2000000 - ORIGIN(ROM) +#else + extern_ram_seg(RWX) : org = 0x3c000020 , len = 0x2000000-0x20 +#endif } #ifdef CONFIG_ESP32S3_RUN_IRAM From 436dbe3f0b1adc4e0e8d6bab6f98061b30140b89 Mon Sep 17 00:00:00 2001 From: Tiago Medicci Serrano Date: Thu, 13 Feb 2025 10:43:19 -0300 Subject: [PATCH 02/33] Documentation/esp32s3: Add ESP32-S3's PSRAM entry Add entry for the external PSRAM support on ESP32-S3 and document how to move data to the external PSRAM to free the internal memory. --- .../platforms/xtensa/esp32s3/index.rst | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Documentation/platforms/xtensa/esp32s3/index.rst b/Documentation/platforms/xtensa/esp32s3/index.rst index a275c4afa904c..195c3e2b8123a 100644 --- a/Documentation/platforms/xtensa/esp32s3/index.rst +++ b/Documentation/platforms/xtensa/esp32s3/index.rst @@ -430,6 +430,30 @@ using WPA2. The ``dhcpd_start`` is necessary to let your board to associate an IP to your smartphone. +PSRAM +----- + +The external PSRAM is supported in ESP32-S3. The PSRAM is mapped to the data bus during +the boot process. The PSRAM is used as a heap memory and is available for the application. + +Please check the following examples for more information: + +* :ref:`esp32s3-devkit:psram_octal ` +* :ref:`esp32s3-devkit:psram_quad ` + +Moving not initialized data to the external PSRAM +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Static or global not-initialized data can be moved to the external PSRAM. Usually allocated at the +``.bss`` memory segment, this data can be set to another section in the external PSRAM. +Set the attribute ``__attribute__ ((section (".ext_ram.bss")))`` to the variable. For example:: + + __attribute__ ((section (".ext_ram.bss"))) static uint8_t my_data[1024]; + +``my_data`` will be allocated in the external PSRAM and can be explicitly initialized on runtime. + +This is particularly useful when the internal RAM is not enough to hold all the data. + Supported Boards ================ From 2ebce06b79a70881bd57a363a33f2d0f50965064 Mon Sep 17 00:00:00 2001 From: Zhu Zhongjie Date: Wed, 19 Feb 2025 09:39:26 +0800 Subject: [PATCH 03/33] board/arm/rp2040: support config st7789 reset gpio pin Signed-off-by: Zhu Zhongjie --- boards/arm/rp2040/common/Kconfig | 6 ++++++ boards/arm/rp2040/common/src/rp2040_st7789.c | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/boards/arm/rp2040/common/Kconfig b/boards/arm/rp2040/common/Kconfig index fd1e7ffafeba2..81b6ee497fa4e 100644 --- a/boards/arm/rp2040/common/Kconfig +++ b/boards/arm/rp2040/common/Kconfig @@ -552,6 +552,12 @@ config RP2040_LCD_SPI_CH range 0 1 ---help--- Select SPI channel number to use LCD display. +config LCD_ST7789_RST_GPIO + int "ST7789 LCD Reset gpio number" + default 12 + range 0 21 + ---help--- + Select Sitronix ST7789 TFT Controller Reset gpio. endif # LCD diff --git a/boards/arm/rp2040/common/src/rp2040_st7789.c b/boards/arm/rp2040/common/src/rp2040_st7789.c index cd644eedd09ae..67fd829aeea7a 100644 --- a/boards/arm/rp2040/common/src/rp2040_st7789.c +++ b/boards/arm/rp2040/common/src/rp2040_st7789.c @@ -48,7 +48,7 @@ #if LCD_SPI_PORTNO #define LCD_DC CONFIG_RP2040_SPI1_RX_GPIO -#define LCD_RST 12 +#define LCD_RST CONFIG_LCD_ST7789_RST_GPIO #define LCD_BL 13 #else #define LCD_DC CONFIG_RP2040_SPI0_RX_GPIO @@ -96,6 +96,7 @@ int board_lcd_initialize(void) rp2040_gpio_init(LCD_RST); rp2040_gpio_setdir(LCD_RST, true); + rp2040_gpio_put(LCD_RST, false); rp2040_gpio_put(LCD_RST, true); /* Set full brightness */ From 6bd191e7e0cf79b7f0f6d78e0f3a22ff3b03c2d7 Mon Sep 17 00:00:00 2001 From: "lijing.ly" Date: Wed, 19 Feb 2025 19:29:21 +0800 Subject: [PATCH 04/33] drivers/rpmsg/Kconfig: Add SPI dependency for RPMSG_PORT_SPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If SPI dependency is not set, the following warning will be generated during compilation: [109/1450] Building C object drivers/CMakeFiles/drivers.dir/rpmsg/rpmsg_port_spi.c.o /data/code/nuttxspace/nuttx/drivers/rpmsg/rpmsg_port_spi.c: In function ‘rpmsg_port_spi_exchange’: /data/code/nuttxspace/nuttx/drivers/rpmsg/rpmsg_port_spi.c:233:3: warning: implicit declaration of function ‘SPI_EXCHANGE’ [-Wimplicit-function-declaration] 233 | SPI_EXCHANGE(rpspi->spi, txhdr, rpspi->rxhdr, | ^~~~~~~~~~~~ [1450/1450] Pac SIM with dynamic libs in nuttx.tgz Signed-off-by: lijing.ly --- drivers/rpmsg/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig index 25dafad396341..3d10914868a7f 100644 --- a/drivers/rpmsg/Kconfig +++ b/drivers/rpmsg/Kconfig @@ -40,6 +40,7 @@ config RPMSG_PORT config RPMSG_PORT_SPI bool "Rpmsg SPI Port Driver Support" default n + depends on SPI select RPMSG_PORT ---help--- Rpmsg SPI Port driver used for cross chip communication. From b4174952843c2ffd9776d02bd4357b118e2c55b9 Mon Sep 17 00:00:00 2001 From: Tiago Medicci Serrano Date: Wed, 25 Sep 2024 14:36:35 -0300 Subject: [PATCH 05/33] arch/risc-v: support backtrace dump during IRQ Adds support for backtrace when the system crashes during IRQ for RISC-V. Tested with SMP, no SMP and no interrupt stack. --- .../src/common/riscv_exception_common.S | 23 +++++++++++ arch/risc-v/src/common/riscv_getintstack.c | 2 +- arch/risc-v/src/common/riscv_macros.S | 22 ++++++++++- arch/risc-v/src/qemu-rv/chip.h | 39 ++++++++++++++++++- 4 files changed, 83 insertions(+), 3 deletions(-) diff --git a/arch/risc-v/src/common/riscv_exception_common.S b/arch/risc-v/src/common/riscv_exception_common.S index 2c60e0c4e1e7c..62cb1eea127e7 100644 --- a/arch/risc-v/src/common/riscv_exception_common.S +++ b/arch/risc-v/src/common/riscv_exception_common.S @@ -207,25 +207,48 @@ handle_irq: .cfi_offset x2, 8 /* Toolchain not support macro, is REG_X2 * 4 */ .cfi_offset ra, 0 /* Toolchain not support macro, is REG_EPC * 4 */ +#ifdef CONFIG_SCHED_BACKTRACE + REGLOAD ra, REG_EPC(sp) + REGLOAD s0, REG_X8(sp) +#endif + #if CONFIG_ARCH_INTERRUPTSTACK > 15 /* Switch to interrupt stack */ setintstack t0, t1 + addi sp, sp, -16 + REGSTORE ra, 12(sp) + REGSTORE s0, 8(sp) + add s0, sp, 16 + /* Call interrupt handler in C */ jal x1, riscv_dispatch_irq + REGLOAD ra, 12(sp) + REGLOAD s0, 8(sp) + add sp, sp, 16 + #else /* Reserve some space for current_regs if interrupt stack disabled */ + addi sp, sp, -16 + REGSTORE ra, 12(sp) + REGSTORE s0, 8(sp) + add s0, sp, 16 + addi sp, sp, -XCPTCONTEXT_SIZE /* Call interrupt handler in C */ jal x1, riscv_dispatch_irq + REGLOAD ra, 12(sp) + REGLOAD s0, 8(sp) + add sp,sp,16 + /* Restore sp */ addi sp, sp, XCPTCONTEXT_SIZE diff --git a/arch/risc-v/src/common/riscv_getintstack.c b/arch/risc-v/src/common/riscv_getintstack.c index e7452c18c94a7..78cadf6882599 100644 --- a/arch/risc-v/src/common/riscv_getintstack.c +++ b/arch/risc-v/src/common/riscv_getintstack.c @@ -41,6 +41,6 @@ #if CONFIG_ARCH_INTERRUPTSTACK > 3 uintptr_t up_get_intstackbase(int cpu) { - return (uintptr_t)g_intstacktop - cpu * INT_STACK_SIZE; + return (uintptr_t)g_intstacktop - ((cpu + 1) * INT_STACK_SIZE); } #endif diff --git a/arch/risc-v/src/common/riscv_macros.S b/arch/risc-v/src/common/riscv_macros.S index ae530fb03dec7..4a0bddc1b9081 100644 --- a/arch/risc-v/src/common/riscv_macros.S +++ b/arch/risc-v/src/common/riscv_macros.S @@ -342,7 +342,27 @@ #if CONFIG_ARCH_INTERRUPTSTACK > 15 #if !defined(CONFIG_SMP) && !defined(CONFIG_ARCH_USE_S_MODE) .macro setintstack tmp0, tmp1 - la sp, g_intstacktop + + /* Load g_intstacktop (the start of the interrupt stack) */ + la \tmp0, g_intstacktop + + /* Load g_intstackalloc (the end of the interrupt stack) */ + la \tmp1, g_intstackalloc + + /* Check if sp is below g_intstackalloc (outside the interrupt stack) */ + blt sp, \tmp1, 1f + + /* Check if sp is above g_intstacktop (outside the interrupt stack) */ + bgt sp, \tmp0, 1f + + /* If sp is within the interrupt stack boundaries, no action is required */ + j 2f + +1: + /* Set sp to g_intstacktop (switch to the interrupt stack) */ + mv sp, \tmp0 + +2: .endm #endif /* !defined(CONFIG_SMP) && !defined(CONFIG_ARCH_USE_S_MODE) */ #endif /* CONFIG_ARCH_INTERRUPTSTACK > 15 */ diff --git a/arch/risc-v/src/qemu-rv/chip.h b/arch/risc-v/src/qemu-rv/chip.h index e62c00e8788ec..b47e3544352f3 100644 --- a/arch/risc-v/src/qemu-rv/chip.h +++ b/arch/risc-v/src/qemu-rv/chip.h @@ -62,7 +62,44 @@ li \tmp1, STACK_ALIGN_DOWN(CONFIG_ARCH_INTERRUPTSTACK) mul \tmp1, \tmp0, \tmp1 la \tmp0, g_intstacktop - sub sp, \tmp0, \tmp1 + + /* tmp0 = g_intstacktop - (CONFIG_ARCH_INTERRUPTSTACK * HART_ID) + * (high address of the interrupt stack) + */ + + sub \tmp0, \tmp0, \tmp1 + li \tmp1, STACK_ALIGN_DOWN(CONFIG_ARCH_INTERRUPTSTACK) + + /* tmp1 = tmp0 - CONFIG_ARCH_INTERRUPTSTACK + * (low address of the interrupt stack) + */ + + sub \tmp1, \tmp0, \tmp1 + + /* Check if sp is below the low address of the interrupt stack + * (outside the interrupt stack). + */ + + blt sp, \tmp1, 1f + + /* Check if sp is above the high address of the interrupt stack + * (outside the interrupt stack) + */ + + bgt sp, \tmp0, 1f + + /* If sp is within the interrupt stack boundaries, no action is required */ + + j 2f + +1: + /* Set sp to the high address of the interrupt stack (start of the + * interrupt stack) + */ + + mv sp, \tmp0 + +2: .endm #endif /* CONFIG_SMP && CONFIG_ARCH_INTERRUPTSTACK > 15 */ From becba7153fb1be5846feb96c2d4317cbb0e75c09 Mon Sep 17 00:00:00 2001 From: Filipe Cavalcanti Date: Fri, 14 Feb 2025 15:40:59 -0300 Subject: [PATCH 06/33] arch/risc-v: improve nested interrupt assertion on riscv_doirq --- arch/risc-v/src/common/riscv_doirq.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/arch/risc-v/src/common/riscv_doirq.c b/arch/risc-v/src/common/riscv_doirq.c index 734087a5c57fe..836aca620a693 100644 --- a/arch/risc-v/src/common/riscv_doirq.c +++ b/arch/risc-v/src/common/riscv_doirq.c @@ -88,13 +88,24 @@ uintreg_t *riscv_doirq(int irq, uintreg_t *regs) (*running_task)->xcp.regs = regs; } - /* Nested interrupts are not supported */ + /* Current regs non-zero indicates that we are processing an interrupt; + * current_regs is also used to manage interrupt level context switches. + * + * Nested interrupts are not supported. But an exception may occur while + * processing an interrupt. In this case, current_regs will be non-NULL. + */ - DEBUGASSERT(!up_interrupt_context()); + DEBUGASSERT(((irq > RISCV_MAX_EXCEPTION) && !up_interrupt_context()) || + (irq <= RISCV_MAX_EXCEPTION)); - /* Set irq flag */ + /* Don't override current regs if it is already set (which is true if + * we were in a interrupt handler). + */ - up_set_interrupt_context(true); + if (!up_interrupt_context()) + { + up_set_interrupt_context(true); + } /* Deliver the IRQ */ From 8de9dd9515b7e4c50c9c92123b0060f639245a84 Mon Sep 17 00:00:00 2001 From: Matteo Golin Date: Tue, 18 Feb 2025 17:14:26 -0500 Subject: [PATCH 07/33] drivers/sensors/lsm6dso32: fixed byte read command to include start. This is required to meet the communication requirements as per the LSM6DSO32 datasheet. It doesn't cause issues on some MCUs (RP2040), but prevents successful reads on others (STM32). Signed-off-by: Matteo Golin --- drivers/sensors/lsm6dso32_uorb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensors/lsm6dso32_uorb.c b/drivers/sensors/lsm6dso32_uorb.c index fbe3b6df0a30f..54b13e519a4fd 100644 --- a/drivers/sensors/lsm6dso32_uorb.c +++ b/drivers/sensors/lsm6dso32_uorb.c @@ -386,7 +386,7 @@ static int lsm6dso32_read_bytes(FAR struct lsm6dso32_dev_s *priv, cmd[1].frequency = CONFIG_SENSORS_LSM6DSO32_I2C_FREQUENCY; cmd[1].addr = priv->addr; - cmd[1].flags = I2C_M_NOSTART | I2C_M_READ; + cmd[1].flags = I2C_M_READ; cmd[1].buffer = buf; cmd[1].length = nbytes; From ff4d461fdaed36db9e6acfe3aabb7b418b0608c2 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Tue, 18 Feb 2025 11:14:05 +0200 Subject: [PATCH 08/33] mpfs_irq.c: Interrupt claim must be cleared before disabling the source From Polarfire SoC TRM: 6.5.8 Interrupt Completion To signal the completion of executing an interrupt handler, the processor core writes the received interrupt ID to the Claim/Complete register. The PLIC does not check whether the completion ID is the same as the last claim ID for that target. If the completion ID does not match an interrupt source that is currently enabled for the target, the completion is ignored. The last paragraph clearly states that IRQ completion does not work for sources that have been disabled -> must ACK the completion before disable. Signed-off-by: Ville Juven --- arch/risc-v/src/mpfs/mpfs_irq.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_irq.c b/arch/risc-v/src/mpfs/mpfs_irq.c index 36b48c7d59a57..b9a7e4a4ebe9b 100644 --- a/arch/risc-v/src/mpfs/mpfs_irq.c +++ b/arch/risc-v/src/mpfs/mpfs_irq.c @@ -133,13 +133,22 @@ void up_disable_irq(int irq) uintptr_t claim_address = mpfs_plic_get_claimbase(riscv_cpuid_to_hartid(i)); - /* Clear enable bit for the irq */ + /* Clear any already claimed IRQ (this must be done BEFORE + * disabling the interrupt source): + * + * To signal the completion of executing an interrupt handler, the + * processor core writes the received interrupt ID to the + * Claim/Complete register. The PLIC does not check whether the + * completion ID is the same as the last claim ID for that target. + * If the completion ID does not match an interrupt source that is + * currently enabled for the target, the completion is ignored. + */ - modifyreg32(iebase + (4 * (extirq / 32)), 1 << (extirq % 32), 0); + putreg32(extirq, claim_address); - /* Clear any already claimed IRQ */ + /* Clear enable bit for the irq */ - putreg32(extirq, claim_address); + modifyreg32(iebase + (4 * (extirq / 32)), 1 << (extirq % 32), 0); } } } From 1d383a243f125079d84613254f9c048c73e966bb Mon Sep 17 00:00:00 2001 From: chao an Date: Wed, 19 Feb 2025 14:23:02 +0800 Subject: [PATCH 09/33] libs/libnx: do not generate resource if CONFIG_NX is not enabled To avoid generate resource if CONFIG_NX is disabled: | $ make -j12 | Create version.h | CPP: nxfonts_convert.c-> nxfonts_convert_8bpp.i | CPP: nxfonts_convert.c-> nxfonts_convert_24bpp.i Signed-off-by: chao an --- libs/libnx/Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libs/libnx/Makefile b/libs/libnx/Makefile index f9ab938f47e8b..7aab39afada94 100644 --- a/libs/libnx/Makefile +++ b/libs/libnx/Makefile @@ -46,6 +46,8 @@ all: $(BIN) .PHONY : context depend clean distclean gensources gen1bppsources gen2bppsource \ gen4bppsource gen8bppsource gen16bppsource gen24bppsource gen32bppsources genfontsources +ifeq ($(CONFIG_NXFONTS),y) + gen1bppsources: $(Q) $(MAKE) -C nxfonts -f Makefile.sources NXFONTS_BITSPERPIXEL=1 EXTRAFLAGS="$(EXTRAFLAGS)" @@ -200,6 +202,9 @@ ifeq ($(CONFIG_NXFONT_TOM_THUMB_4X6),y) endif gensources: gen1bppsources gen2bppsource gen4bppsource gen8bppsource gen16bppsource gen24bppsource gen32bppsources genfontsources +else +gensources: +endif $(AOBJS): $(BINDIR)$(DELIM)%$(OBJEXT): %.S $(call ASSEMBLE, $<, $@) From ff1dc9583f843879a7aac06821e0d9ff472ec8b4 Mon Sep 17 00:00:00 2001 From: chao an Date: Wed, 19 Feb 2025 10:34:27 +0800 Subject: [PATCH 10/33] libc/libcxx: fix failures with GCC 14 CXX: libcxx/libcxx/src/random.cpp In file included from nuttx/include/libcxx/__filesystem/filesystem_error.h:15, from nuttx/include/libcxx/__filesystem/directory_entry.h:20, from nuttx/include/libcxx/filesystem:539, from nuttx/include/libcxx/fstream:192, from libcxx/libcxx/src/ios.instantiations.cpp:10: nuttx/include/libcxx/__filesystem/path.h: In instantiation of 'std::__1::__fs::filesystem::path::_EnableIfPathable<_Source> std::__1::__fs::filesystem::path::append(const _Source&) [with _Source = std::__1::basic_string]': nuttx/include/libcxx/__filesystem/path.h:623:30: error: use of built-in trait '__remove_pointer(typename std::__1::decay<_Tp>::type)' in function signature; use library traits instead 623 | _EnableIfPathable<_Source> append(const _Source& __src) { | ^~~~~~ Pick the change from llvm-project: https://github.com/llvm/llvm-project/pull/92663 Signed-off-by: chao an --- ...-libc-Fix-failures-with-GCC-14-92663.patch | 35 +++++++++++++++++++ libs/libxx/libcxx/CMakeLists.txt | 4 ++- libs/libxx/libcxx/Make.defs | 1 + 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 libs/libxx/libcxx/0001-libc-Fix-failures-with-GCC-14-92663.patch diff --git a/libs/libxx/libcxx/0001-libc-Fix-failures-with-GCC-14-92663.patch b/libs/libxx/libcxx/0001-libc-Fix-failures-with-GCC-14-92663.patch new file mode 100644 index 0000000000000..9687db50221f8 --- /dev/null +++ b/libs/libxx/libcxx/0001-libc-Fix-failures-with-GCC-14-92663.patch @@ -0,0 +1,35 @@ +From cb7a03b41fff563c0cbb5145eed09f9b17edf9e2 Mon Sep 17 00:00:00 2001 +From: Nikolas Klauser +Date: Sat, 1 Jun 2024 12:20:41 +0200 +Subject: [PATCH] [libc++] Fix failures with GCC 14 (#92663) + +Fixes #91831 + +Signed-off-by: chao an + +--- + libcxx/include/__type_traits/remove_pointer.h | 5 +++++ + 11 files changed, 22 insertions(+), 8 deletions(-) + +diff --git libcxx/include/__type_traits/remove_pointer.h b/libcxx/include/__type_traits/remove_pointer.h +index 54390a1939f7..1048f67055a2 100644 +--- libcxx/include/__type_traits/remove_pointer.h ++++ libcxx/include/__type_traits/remove_pointer.h +@@ -23,8 +23,13 @@ struct remove_pointer { + using type _LIBCPP_NODEBUG = __remove_pointer(_Tp); + }; + ++# ifdef _LIBCPP_COMPILER_GCC ++template ++using __remove_pointer_t = typename remove_pointer<_Tp>::type; ++# else + template + using __remove_pointer_t = __remove_pointer(_Tp); ++# endif + #else + // clang-format off + template struct _LIBCPP_TEMPLATE_VIS remove_pointer {typedef _LIBCPP_NODEBUG _Tp type;}; + +-- +2.43.0 + diff --git a/libs/libxx/libcxx/CMakeLists.txt b/libs/libxx/libcxx/CMakeLists.txt index 6194abfa16816..664600337647f 100644 --- a/libs/libxx/libcxx/CMakeLists.txt +++ b/libs/libxx/libcxx/CMakeLists.txt @@ -52,7 +52,9 @@ if(CONFIG_LIBCXX) -p1 -d ${CMAKE_CURRENT_LIST_DIR}/libcxx < ${CMAKE_CURRENT_LIST_DIR}/0001-libcxx-fix-ld-errors.patch && patch -p1 -d ${CMAKE_CURRENT_LIST_DIR}/libcxx < - ${CMAKE_CURRENT_LIST_DIR}/0001-Fix-build-error-about-__GLIBC__.patch + ${CMAKE_CURRENT_LIST_DIR}/0001-Fix-build-error-about-__GLIBC__.patch && + patch -p1 -d ${CMAKE_CURRENT_LIST_DIR}/libcxx < + ${CMAKE_CURRENT_LIST_DIR}/0001-libc-Fix-failures-with-GCC-14-92663.patch DOWNLOAD_NO_PROGRESS true TIMEOUT 30) diff --git a/libs/libxx/libcxx/Make.defs b/libs/libxx/libcxx/Make.defs index 62f4fba8a7e22..e5cc01af997b0 100644 --- a/libs/libxx/libcxx/Make.defs +++ b/libs/libxx/libcxx/Make.defs @@ -36,6 +36,7 @@ libcxx/libcxx: libcxx-$(LIBCXX_VERSION).src.tar.xz $(Q) patch -p0 < libcxx/0001-libcxx-remove-mach-time-h.patch -d libcxx $(Q) patch -p0 < libcxx/0001-libcxx-fix-ld-errors.patch -d libcxx $(Q) patch -p0 < libcxx/0001-Fix-build-error-about-__GLIBC__.patch -d libcxx + $(Q) patch -p0 < libcxx/0001-libc-Fix-failures-with-GCC-14-92663.patch -d libcxx endif From a76d63646fdc7fd8eaae0543c433e850c69b6c7a Mon Sep 17 00:00:00 2001 From: Matteo Golin Date: Wed, 19 Feb 2025 17:28:49 -0500 Subject: [PATCH 11/33] drivers/sensors/ms56xx: Use nxsig_usleep for long delays. Change use of `up_udelay()` to `nxsig_usleep()` on the 10ms delays for better performance. Signed-off-by: Matteo Golin --- drivers/sensors/ms56xx_uorb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/sensors/ms56xx_uorb.c b/drivers/sensors/ms56xx_uorb.c index 645cbf46a10a6..669875d34c4d3 100644 --- a/drivers/sensors/ms56xx_uorb.c +++ b/drivers/sensors/ms56xx_uorb.c @@ -286,7 +286,7 @@ static inline void baro_measure_read(FAR struct ms56xx_dev_s *priv, /* Wait data acquisition */ - up_udelay(10000); + nxsig_usleep(10000); /* Send command to start a read sequence */ @@ -323,7 +323,7 @@ static inline void baro_measure_read(FAR struct ms56xx_dev_s *priv, /* Wait data acquisition */ - up_udelay(10000); + nxsig_usleep(10000); /* Send command to start a read sequence */ @@ -437,7 +437,7 @@ static int ms56xx_initialize(FAR struct ms56xx_dev_s *priv) /* We have to wait before the prom is ready is be read */ - up_udelay(10000); + nxsig_usleep(10000); for (i = 0; i < 8; i++) { From 3170af2fd0a827fafbf2d5274dbc22e2bd242466 Mon Sep 17 00:00:00 2001 From: Eren Terzioglu Date: Mon, 17 Feb 2025 09:53:29 +0100 Subject: [PATCH 12/33] esp32[c6|h2]: Update peripheral support docs --- Documentation/platforms/risc-v/esp32c6/index.rst | 4 ++-- Documentation/platforms/risc-v/esp32h2/index.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/platforms/risc-v/esp32c6/index.rst b/Documentation/platforms/risc-v/esp32c6/index.rst index bd98d966e6ec8..c6049e3719f05 100644 --- a/Documentation/platforms/risc-v/esp32c6/index.rst +++ b/Documentation/platforms/risc-v/esp32c6/index.rst @@ -283,12 +283,12 @@ GPIO Yes HMAC No I2C Yes I2S No -Int. Temp. No +Int. Temp. Yes LED No LED_PWM Yes MCPWM Yes Pulse Counter Yes -RMT No +RMT Yes RNG No RSA No RTC Yes diff --git a/Documentation/platforms/risc-v/esp32h2/index.rst b/Documentation/platforms/risc-v/esp32h2/index.rst index 95a2d0aef868a..7fff0591a0730 100644 --- a/Documentation/platforms/risc-v/esp32h2/index.rst +++ b/Documentation/platforms/risc-v/esp32h2/index.rst @@ -283,12 +283,12 @@ GPIO Yes HMAC No I2C Yes I2S No -Int. Temp. No +Int. Temp. Yes LED No LED_PWM Yes MCPWM No Pulse Counter Yes -RMT No +RMT Yes RNG No RSA No RTC Yes From 2d069231c54605ec0907704ae758fcc3acb7cf6f Mon Sep 17 00:00:00 2001 From: Eren Terzioglu Date: Mon, 17 Feb 2025 11:42:21 +0100 Subject: [PATCH 13/33] esp32[s3]: Add Documentation for esp32s3-lcd-ev board --- .../esp32s3-audio-config-file.png | Bin 0 -> 21276 bytes .../boards/esp32s3-lcd-ev/esp32s3_lcd_ev.png | Bin 0 -> 338946 bytes .../esp32s3/boards/esp32s3-lcd-ev/index.rst | 156 ++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 Documentation/platforms/xtensa/esp32s3/boards/esp32s3-lcd-ev/esp32s3-audio-config-file.png create mode 100644 Documentation/platforms/xtensa/esp32s3/boards/esp32s3-lcd-ev/esp32s3_lcd_ev.png create mode 100644 Documentation/platforms/xtensa/esp32s3/boards/esp32s3-lcd-ev/index.rst diff --git a/Documentation/platforms/xtensa/esp32s3/boards/esp32s3-lcd-ev/esp32s3-audio-config-file.png b/Documentation/platforms/xtensa/esp32s3/boards/esp32s3-lcd-ev/esp32s3-audio-config-file.png new file mode 100644 index 0000000000000000000000000000000000000000..c51fa32e29db74ad0e4ddd96042948f03527fa0b GIT binary patch literal 21276 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 S*>?aY#P;;rQx#U168;AO3v{#q literal 0 HcmV?d00001 diff --git a/Documentation/platforms/xtensa/esp32s3/boards/esp32s3-lcd-ev/esp32s3_lcd_ev.png b/Documentation/platforms/xtensa/esp32s3/boards/esp32s3-lcd-ev/esp32s3_lcd_ev.png new file mode 100644 index 0000000000000000000000000000000000000000..23be064d3ac9305eb4c48c0907c64682c9c4dff2 GIT binary patch literal 338946 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�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 is a small-sized AI development board from Espressif featuring the ESP32-S3 CPU with a touchscreen LCD display, dual microphone, an 16 MB Octal PSRAM and an 16 MB flash. + +.. list-table:: + :align: center + + * - .. figure:: esp32s3_lcd_ev.png + :align: center + +Features +======== + + - ESP32-S3 WROOM-1 Module + - USB Type-C ports + - Power LED + - LCD Display + - MEMS Microphone + - 16MB Octal PSRAM + - 16MB SPI Flash + - RST and BOOT buttons (BOOT accessible to user) + +Serial Console +============== + +UART0 is, by default, the serial console. It connects to the on-board +CP2102 converter and is available on the USB connector USB CON8 (J1). + +It will show up as /dev/ttyUSB[n] where [n] will probably be 0. + +Buttons and LEDs +================ + +Board Buttons +------------- + +There are two buttons labeled Boot and EN. The EN button is not available +to software. It pulls the chip enable line that doubles as a reset line. + +The BOOT button is connected to IO0. On reset it is used as a strapping +pin to determine whether the chip boots normally or into the serial +bootloader. After reset, however, the BOOT button can be used for software +input. + +Board LEDs +---------- + +There are several on-board LEDs for that indicate the presence of power +and USB activity. None of these are available for use by software. +Another WS2812 LED is connected to GPIO4. + +Configurations +============== + +All of the configurations presented below can be tested by running the following commands:: + + $ ./tools/configure.sh esp32s3-lcd-ev: + $ make flash ESPTOOL_PORT=/dev/ttyUSB0 -j + +Where is the name of board configuration you want to use, i.e.: nsh, buttons, wifi... +Then use a serial console terminal like ``picocom`` configured to 115200 8N1. + +audio +----- + +This configuration uses the I2S0 peripheral and an externally connected audio +codec to play an audio file streamed over an HTTP connection while connected +to a Wi-Fi network. + +**Audio Codec Setup** + +The CS4344 audio codec is connected to the following pins: + +============ ========== ============================================ +ESP32-S3 Pin CS4344 Pin Description +============ ========== ============================================ +5 MCLK Master Clock +16 SCLK Serial Clock +7 LRCK Left Right Clock (Word Select) +6 SDIN Serial Data In on CS4344. (DOUT on ESP32-S3) +============ ========== ============================================ + +**Simple HTTP server** + +Prepare a PCM-encoded (`.wav`) audio file with 16 or 24 bits/sample (sampled at +16~48kHz). This file must be placed into a folder in a computer that could +be accessed on the same Wi-Fi network the ESP32 will be connecting to. + +Python provides a simple HTTP server. ``cd`` to the audio file folder on the +PC and run:: + + $ python3 -m http.server + Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) + +Look for your PC IP address and test playing the prepared audio on your +browser: + +.. figure:: esp32s3-audio-config-file.png + :align: center + +After successfully built and flashed, connect the board to the Wi-Fi network:: + + nsh> wapi psk wlan0 mypasswd 3 + nsh> wapi essid wlan0 myssid 1 + nsh> renew wlan0 + +Once connected, open NuttX's player and play the file according to the filename +and the IP address of the HTTP server:: + + nsh> nxplayer + nxplayer> play http://192.168.1.239:8000/tones.wav + +buttons +------- + +This configuration shows the use of the buttons subsystem. It can be used by executing +the ``buttons`` application and pressing on any of the available board buttons:: + + nsh> buttons + buttons_main: Starting the button_daemon + buttons_main: button_daemon started + button_daemon: Running + button_daemon: Opening /dev/buttons + button_daemon: Supported BUTTONs 0x01 + nsh> Sample = 1 + Sample = 0 + +lvgl +---- + +This is a demonstration of the LVGL graphics library running on the NuttX LCD +driver. You can find LVGL here:: + + https://www.lvgl.io/ + https://github.com/lvgl/lvgl + +This configuration uses the LVGL demonstration at `apps/examples/lvgldemo`. + +nsh +--- + +Basic NuttShell configuration (console enabled in UART0, exposed via +USB connection by means of CP2102 converter, at 115200 bps). + +ws2812 +------ + +This configuration enables the usage of the RMT peripheral and the example +``ws2812`` to drive addressable RGB LEDs:: + + nsh> ws2812 + +Please note that this board contains an on-board WS2812 LED connected to GPIO38 +and, by default, this config configures the RMT transmitter in the same pin. From f286a63223924ca863add512b430644aaa9c8748 Mon Sep 17 00:00:00 2001 From: Eren Terzioglu Date: Thu, 30 Jan 2025 11:02:42 +0100 Subject: [PATCH 14/33] esp32[c3|c6|h2]: Add DMA function to have more capabilites Add DMA function to increase DMA peripheral capabilities Signed-off-by: Eren Terzioglu --- arch/risc-v/src/common/espressif/esp_dma.c | 146 +++++++++++++++++++++ arch/risc-v/src/common/espressif/esp_dma.h | 88 +++++++++++++ 2 files changed, 234 insertions(+) diff --git a/arch/risc-v/src/common/espressif/esp_dma.c b/arch/risc-v/src/common/espressif/esp_dma.c index 233b717c251e0..c501ef853ba71 100644 --- a/arch/risc-v/src/common/espressif/esp_dma.c +++ b/arch/risc-v/src/common/espressif/esp_dma.c @@ -282,6 +282,125 @@ void esp_dma_load(struct esp_dmadesc_s *dmadesc, int chan, bool tx) } } +/**************************************************************************** + * Name: esp_dma_enable_interrupt + * + * Description: + * Enable/Disable DMA interrupt. + * + * Input Parameters: + * chan - DMA channel + * tx - true: TX mode; false: RX mode + * mask - Interrupt mask to change + * en - true: enable; false: disable + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp_dma_enable_interrupt(int chan, bool tx, uint32_t mask, bool en) +{ + if (tx) + { + gdma_ll_tx_enable_interrupt(ctx.dev, chan, mask, en); + } + else + { + gdma_ll_rx_enable_interrupt(ctx.dev, chan, mask, en); + } +} + +/**************************************************************************** + * Name: esp_dma_get_interrupt + * + * Description: + * Gets DMA interrupt status. + * + * Input Parameters: + * chan - DMA channel + * tx - true: TX mode; false: RX mode + * + * Returned Value: + * Interrupt status value. + * + ****************************************************************************/ + +int esp_dma_get_interrupt(int chan, bool tx) +{ + uint32_t intr_status = 0; + + if (tx) + { + intr_status = gdma_ll_tx_get_interrupt_status(ctx.dev, chan); + } + else + { + intr_status = gdma_ll_rx_get_interrupt_status(ctx.dev, chan); + } + + return intr_status; +} + +/**************************************************************************** + * Name: esp_dma_clear_interrupt + * + * Description: + * Clear DMA interrupt. + * + * Input Parameters: + * chan - DMA channel + * tx - true: TX mode; false: RX mode + * mask - Interrupt mask to change + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp_dma_clear_interrupt(int chan, bool tx, uint32_t mask) +{ + if (tx) + { + gdma_ll_tx_clear_interrupt_status(ctx.dev, chan, mask); + } + else + { + gdma_ll_rx_clear_interrupt_status(ctx.dev, chan, mask); + } +} + +/**************************************************************************** + * Name: esp_dma_get_desc_addr + * + * Description: + * Gets desc addr of DMA interrupt. + * + * Input Parameters: + * chan - DMA channel + * tx - true: TX mode; false: RX mode + * + * Returned Value: + * Desc addr. + * + ****************************************************************************/ + +int esp_dma_get_desc_addr(int chan, bool tx) +{ + uint32_t desc_addr = 0; + + if (tx) + { + desc_addr = gdma_ll_tx_get_eof_desc_addr(ctx.dev, chan); + } + else + { + desc_addr = gdma_ll_rx_get_success_eof_desc_addr(ctx.dev, chan); + } + + return desc_addr; +} + /**************************************************************************** * Name: esp_dma_enable * @@ -363,6 +482,33 @@ void esp_dma_wait_idle(int chan, bool tx) } } +/**************************************************************************** + * Name: esp_dma_reset_channel + * + * Description: + * Resets dma channel. + * + * Input Parameters: + * chan - DMA channel + * tx - true: TX mode; false: RX mode + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp_dma_reset_channel(int chan, bool tx) +{ + if (tx) + { + gdma_ll_tx_reset_channel(ctx.dev, chan); + } + else + { + gdma_ll_rx_reset_channel(ctx.dev, chan); + } +} + /**************************************************************************** * Name: esp_dma_init * diff --git a/arch/risc-v/src/common/espressif/esp_dma.h b/arch/risc-v/src/common/espressif/esp_dma.h index d1b43156ebfc0..57b2ded6b79d5 100644 --- a/arch/risc-v/src/common/espressif/esp_dma.h +++ b/arch/risc-v/src/common/espressif/esp_dma.h @@ -150,6 +150,77 @@ uint32_t esp_dma_setup(int chan, bool tx, void esp_dma_load(struct esp_dmadesc_s *dmadesc, int chan, bool tx); +/**************************************************************************** + * Name: esp_dma_enable_interrupt + * + * Description: + * Enable DMA interrupt. + * + * Input Parameters: + * chan - DMA channel + * tx - true: TX mode; false: RX mode + * mask - Interrupt mask to change + * en - true: enable; false: disable + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp_dma_enable_interrupt(int chan, bool tx, uint32_t mask, bool en); + +/**************************************************************************** + * Name: esp_dma_get_interrupt + * + * Description: + * Gets DMA interrupt status. + * + * Input Parameters: + * chan - DMA channel + * tx - true: TX mode; false: RX mode + * + * Returned Value: + * Interrupt status value. + * + ****************************************************************************/ + +int esp_dma_get_interrupt(int chan, bool tx); + +/**************************************************************************** + * Name: esp_dma_clear_interrupt + * + * Description: + * Clear DMA interrupt. + * + * Input Parameters: + * chan - DMA channel + * tx - true: TX mode; false: RX mode + * mask - Interrupt mask to change + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp_dma_clear_interrupt(int chan, bool tx, uint32_t mask); + +/**************************************************************************** + * Name: esp_dma_get_desc_addr + * + * Description: + * Gets desc addr of DMA interrupt. + * + * Input Parameters: + * chan - DMA channel + * tx - true: TX mode; false: RX mode + * + * Returned Value: + * Desc addr. + * + ****************************************************************************/ + +int esp_dma_get_desc_addr(int chan, bool tx); + /**************************************************************************** * Name: esp_dma_enable * @@ -201,6 +272,23 @@ void esp_dma_disable(int chan, bool tx); void esp_dma_wait_idle(int chan, bool tx); +/**************************************************************************** + * Name: esp_dma_reset_channel + * + * Description: + * Resets dma channel. + * + * Input Parameters: + * chan - DMA channel + * tx - true: TX mode; false: RX mode + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp_dma_reset_channel(int chan, bool tx); + /**************************************************************************** * Name: esp_dma_init * From 3661cdeed9afaec0cc3b4db989fa43b15818c57a Mon Sep 17 00:00:00 2001 From: Eren Terzioglu Date: Thu, 23 Jan 2025 09:54:29 +0100 Subject: [PATCH 15/33] esp32[c3|c6|h2]: Add I2S support Add I2S support for risc-v based Espressif devices Signed-off-by: Eren Terzioglu --- .../esp32c3/boards/esp32c3-generic/index.rst | 23 + .../esp32c6/boards/esp32c6-devkitc/index.rst | 23 + .../esp32c6/boards/esp32c6-devkitm/index.rst | 23 + .../platforms/risc-v/esp32c6/index.rst | 2 +- .../esp32h2/boards/esp32h2-devkit/index.rst | 23 + .../platforms/risc-v/esp32h2/index.rst | 2 +- arch/risc-v/src/common/espressif/Kconfig | 132 + arch/risc-v/src/common/espressif/Make.defs | 4 + arch/risc-v/src/common/espressif/esp_i2s.c | 2926 +++++++++++++++++ arch/risc-v/src/common/espressif/esp_i2s.h | 76 + arch/risc-v/src/esp32c3/hal_esp32c3.mk | 3 + arch/risc-v/src/esp32c6/hal_esp32c6.mk | 3 + arch/risc-v/src/esp32h2/hal_esp32h2.mk | 3 + .../esp32c3/common/include/esp_board_i2s.h | 76 + boards/risc-v/esp32c3/common/src/Make.defs | 4 + .../risc-v/esp32c3/common/src/esp_board_i2s.c | 200 ++ .../esp32c3-generic/configs/i2schar/defconfig | 62 + .../esp32c3-generic/src/esp32c3_bringup.c | 14 + .../esp32c6/common/include/esp_board_i2s.h | 76 + boards/risc-v/esp32c6/common/src/Make.defs | 4 + .../risc-v/esp32c6/common/src/esp_board_i2s.c | 200 ++ .../esp32c6-devkitc/configs/i2schar/defconfig | 64 + .../esp32c6-devkitc/src/esp32c6_bringup.c | 14 + .../esp32c6-devkitm/configs/i2schar/defconfig | 64 + .../esp32c6-devkitm/src/esp32c6_bringup.c | 14 + .../esp32h2/common/include/esp_board_i2s.h | 76 + boards/risc-v/esp32h2/common/src/Make.defs | 4 + .../risc-v/esp32h2/common/src/esp_board_i2s.c | 200 ++ .../esp32h2-devkit/configs/i2schar/defconfig | 63 + .../esp32h2-devkit/src/esp32h2_bringup.c | 14 + 30 files changed, 4390 insertions(+), 2 deletions(-) create mode 100644 arch/risc-v/src/common/espressif/esp_i2s.c create mode 100644 arch/risc-v/src/common/espressif/esp_i2s.h create mode 100644 boards/risc-v/esp32c3/common/include/esp_board_i2s.h create mode 100644 boards/risc-v/esp32c3/common/src/esp_board_i2s.c create mode 100644 boards/risc-v/esp32c3/esp32c3-generic/configs/i2schar/defconfig create mode 100644 boards/risc-v/esp32c6/common/include/esp_board_i2s.h create mode 100644 boards/risc-v/esp32c6/common/src/esp_board_i2s.c create mode 100644 boards/risc-v/esp32c6/esp32c6-devkitc/configs/i2schar/defconfig create mode 100644 boards/risc-v/esp32c6/esp32c6-devkitm/configs/i2schar/defconfig create mode 100644 boards/risc-v/esp32h2/common/include/esp_board_i2s.h create mode 100644 boards/risc-v/esp32h2/common/src/esp_board_i2s.c create mode 100644 boards/risc-v/esp32h2/esp32h2-devkit/configs/i2schar/defconfig diff --git a/Documentation/platforms/risc-v/esp32c3/boards/esp32c3-generic/index.rst b/Documentation/platforms/risc-v/esp32c3/boards/esp32c3-generic/index.rst index 1a35aaca8cdb7..795f40e5df93b 100644 --- a/Documentation/platforms/risc-v/esp32c3/boards/esp32c3-generic/index.rst +++ b/Documentation/platforms/risc-v/esp32c3/boards/esp32c3-generic/index.rst @@ -208,6 +208,29 @@ You can scan for all I2C devices using the following command:: nsh> i2c dev 0x00 0x7f +i2schar +------- + +This configuration enables the I2S character device and the i2schar example +app, which provides an easy-to-use way of testing the I2S peripheral, +enabling both the TX and the RX for those peripherals. + +**I2S pinout** + +============ ========== ========================================= +ESP32-C3 Pin Signal Pin Description +============ ========== ========================================= +0 MCLK Master Clock +4 SCLK Bit Clock (SCLK) +5 LRCK Word Select (LRCLK) +18 DOUT Data Out +19 DIN Data In +============ ========== ========================================= + +After successfully built and flashed, run on the boards's terminal:: + + nsh> i2schar + nimble ------ diff --git a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst index 05afe6720bf45..d5be28f55ff78 100644 --- a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst +++ b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst @@ -191,6 +191,29 @@ You can scan for all I2C devices using the following command:: nsh> i2c dev 0x00 0x7f +i2schar +------- + +This configuration enables the I2S character device and the i2schar example +app, which provides an easy-to-use way of testing the I2S peripheral, +enabling both the TX and the RX for those peripherals. + +**I2S pinout** + +============ ========== ========================================= +ESP32-C3 Pin Signal Pin Description +============ ========== ========================================= +0 MCLK Master Clock +4 SCLK Bit Clock (SCLK) +5 LRCK Word Select (LRCLK) +18 DOUT Data Out +19 DIN Data In +============ ========== ========================================= + +After successfully built and flashed, run on the boards's terminal:: + + nsh> i2schar + motor ------- diff --git a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitm/index.rst b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitm/index.rst index e8a5f19c00272..99997f0efe848 100644 --- a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitm/index.rst +++ b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitm/index.rst @@ -175,6 +175,29 @@ You can scan for all I2C devices using the following command:: nsh> i2c dev 0x00 0x7f +i2schar +------- + +This configuration enables the I2S character device and the i2schar example +app, which provides an easy-to-use way of testing the I2S peripheral, +enabling both the TX and the RX for those peripherals. + +**I2S pinout** + +============ ========== ========================================= +ESP32-C3 Pin Signal Pin Description +============ ========== ========================================= +0 MCLK Master Clock +4 SCLK Bit Clock (SCLK) +5 LRCK Word Select (LRCLK) +18 DOUT Data Out +19 DIN Data In +============ ========== ========================================= + +After successfully built and flashed, run on the boards's terminal:: + + nsh> i2schar + mcuboot_nsh -------------------- diff --git a/Documentation/platforms/risc-v/esp32c6/index.rst b/Documentation/platforms/risc-v/esp32c6/index.rst index c6049e3719f05..b5b9a434bbd6c 100644 --- a/Documentation/platforms/risc-v/esp32c6/index.rst +++ b/Documentation/platforms/risc-v/esp32c6/index.rst @@ -282,7 +282,7 @@ eFuse Yes GPIO Yes HMAC No I2C Yes -I2S No +I2S Yes Int. Temp. Yes LED No LED_PWM Yes diff --git a/Documentation/platforms/risc-v/esp32h2/boards/esp32h2-devkit/index.rst b/Documentation/platforms/risc-v/esp32h2/boards/esp32h2-devkit/index.rst index 7963b4382fee4..c1a378e57e5e5 100644 --- a/Documentation/platforms/risc-v/esp32h2/boards/esp32h2-devkit/index.rst +++ b/Documentation/platforms/risc-v/esp32h2/boards/esp32h2-devkit/index.rst @@ -174,6 +174,29 @@ You can scan for all I2C devices using the following command:: nsh> i2c dev 0x00 0x7f +i2schar +------- + +This configuration enables the I2S character device and the i2schar example +app, which provides an easy-to-use way of testing the I2S peripheral, +enabling both the TX and the RX for those peripherals. + +**I2S pinout** + +============ ========== ========================================= +ESP32-C3 Pin Signal Pin Description +============ ========== ========================================= +0 MCLK Master Clock +4 SCLK Bit Clock (SCLK) +5 LRCK Word Select (LRCLK) +10 DOUT Data Out +11 DIN Data In +============ ========== ========================================= + +After successfully built and flashed, run on the boards's terminal:: + + nsh> i2schar + mcuboot_nsh -------------------- diff --git a/Documentation/platforms/risc-v/esp32h2/index.rst b/Documentation/platforms/risc-v/esp32h2/index.rst index 7fff0591a0730..7e46177a2422e 100644 --- a/Documentation/platforms/risc-v/esp32h2/index.rst +++ b/Documentation/platforms/risc-v/esp32h2/index.rst @@ -282,7 +282,7 @@ eFuse Yes GPIO Yes HMAC No I2C Yes -I2S No +I2S Yes Int. Temp. Yes LED No LED_PWM Yes diff --git a/arch/risc-v/src/common/espressif/Kconfig b/arch/risc-v/src/common/espressif/Kconfig index 454112abd0e42..a7691714598f4 100644 --- a/arch/risc-v/src/common/espressif/Kconfig +++ b/arch/risc-v/src/common/espressif/Kconfig @@ -321,6 +321,19 @@ config ESPRESSIF_LEDC select PWM select ARCH_HAVE_PWM_MULTICHAN +config ESPRESSIF_I2S + bool + default n + +config ESPRESSIF_I2S0 + bool "I2S 0" + default n + select ESPRESSIF_I2S + select I2S + select ESPRESSIF_DMA + select ESPRESSIF_GPIO_IRQ + select SCHED_HPWORK + config ESPRESSIF_I2C bool default n @@ -1647,6 +1660,125 @@ endif # PWM_MULTICHAN && PWM_NCHANNELS > 1 endmenu # LEDC configuration +menu "I2S Configuration" + depends on ESPRESSIF_I2S + +config ESPRESSIF_I2S_MAXINFLIGHT + int "I2S queue size" + default 4 + ---help--- + This is the total number of transfers, both RX and TX, that can be + enqueued before the caller is required to wait. This setting + determines the number certain queue data structures that will be + pre-allocated. + +if ESPRESSIF_I2S0 + +config ESPRESSIF_I2S0_RX + bool "Enable I2S receiver" + default y + ---help--- + Enable I2S receiver (port 0) + +config ESPRESSIF_I2S0_TX + bool "Enable I2S transmitter" + default y + ---help--- + Enable I2S transmitter (port 0) + +choice ESPRESSIF_I2S0_ROLE + prompt "I2S0 role" + default ESPRESSIF_I2S0_ROLE_MASTER + ---help--- + Selects the operation role of the I2S0. + +config ESPRESSIF_I2S0_ROLE_MASTER + bool "Master" + +config ESPRESSIF_I2S0_ROLE_SLAVE + bool "Slave" + +endchoice # I2S0 role + +choice ESPRESSIF_I2S0_DATA_BIT_WIDTH + prompt "Bit width" + default ESPRESSIF_I2S0_DATA_BIT_WIDTH_16BIT + ---help--- + Selects the valid data bits per sample. + Note that this option may be overwritten by the audio + according to the bit width of the file being played + +config ESPRESSIF_I2S0_DATA_BIT_WIDTH_8BIT + bool "8 bits" + +config ESPRESSIF_I2S0_DATA_BIT_WIDTH_16BIT + bool "16 bits" + +config ESPRESSIF_I2S0_DATA_BIT_WIDTH_24BIT + bool "24 bits" + +config ESPRESSIF_I2S0_DATA_BIT_WIDTH_32BIT + bool "32 bits" + +endchoice # Bit width + +config ESPRESSIF_I2S0_SAMPLE_RATE + int "I2S0 sample rate" + default 44100 + range 8000 48000 + ---help--- + Selects the sample rate. + Note that this option may be overwritten by the audio + according to the bit width of the file being played + +config ESPRESSIF_I2S0_BCLKPIN + int "I2S0 BCLK pin" + default 4 + range 0 48 + +config ESPRESSIF_I2S0_WSPIN + int "I2S0 WS pin" + default 5 + range 0 48 + +config ESPRESSIF_I2S0_DINPIN + int "I2S0 DIN pin" + depends on ESPRESSIF_I2S0_RX + default 19 if !ESPRESSIF_ESP32H2 + default 11 if ESPRESSIF_ESP32H2 + range 0 48 + +config ESPRESSIF_I2S0_DOUTPIN + int "I2S0 DOUT pin" + depends on ESPRESSIF_I2S0_TX + default 18 if !ESPRESSIF_ESP32H2 + default 10 if ESPRESSIF_ESP32H2 + range 0 48 + +config ESPRESSIF_I2S0_MCLK + bool "Enable I2S Master Clock" + depends on ESPRESSIF_I2S0_ROLE_MASTER + default n + ---help--- + Enable I2S master clock + +config ESPRESSIF_I2S0_MCLKPIN + int "I2S MCLK pin" + depends on ESPRESSIF_I2S0_MCLK + default 0 + range 0 48 + +endif # ESPRESSIF_I2S0 + +config I2S_DMADESC_NUM + int "I2S DMA maximum number of descriptors" + default 2 + ---help--- + Configure the maximum number of out-link/in-link descriptors to + be chained for an I2S DMA transfer. + +endmenu # I2S configuration + menu "I2C Configuration" depends on ESPRESSIF_I2C diff --git a/arch/risc-v/src/common/espressif/Make.defs b/arch/risc-v/src/common/espressif/Make.defs index 132bcf0c7a554..a5d0ddf76aeb3 100644 --- a/arch/risc-v/src/common/espressif/Make.defs +++ b/arch/risc-v/src/common/espressif/Make.defs @@ -116,6 +116,10 @@ ifeq ($(CONFIG_ESPRESSIF_I2C),y) endif endif +ifeq ($(CONFIG_ESPRESSIF_I2S),y) +CHIP_CSRCS += esp_i2s.c +endif + ifeq ($(CONFIG_ESPRESSIF_SPI),y) ifeq ($(CONFIG_ESPRESSIF_SPI_PERIPH),y) CHIP_CSRCS += esp_spi.c diff --git a/arch/risc-v/src/common/espressif/esp_i2s.c b/arch/risc-v/src/common/espressif/esp_i2s.c new file mode 100644 index 0000000000000..4b79c093a2528 --- /dev/null +++ b/arch/risc-v/src/common/espressif/esp_i2s.c @@ -0,0 +1,2926 @@ +/**************************************************************************** + * arch/risc-v/src/common/espressif/esp_i2s.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "riscv_internal.h" + +#include "esp_gpio.h" +#include "esp_irq.h" +#include "esp_dma.h" +#include "esp_i2s.h" + +#include "hal/i2s_hal.h" +#include "hal/i2s_ll.h" +#include "soc/i2s_periph.h" +#include "soc/i2s_reg.h" +#include "hal/i2s_types.h" +#include "soc/gpio_sig_map.h" +#include "soc/gdma_reg.h" +#include "periph_ctrl.h" + +#include "esp_attr.h" +#include "esp_bit_defs.h" +#include "esp_cpu.h" +#include "esp_rom_sys.h" +#include "riscv/interrupt.h" +#include "soc/soc.h" +#include "hal/dma_types.h" +#include "soc/gdma_periph.h" +#include "hal/gdma_ll.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_ESPRESSIF_ESP32C6 +# define ETS_I2S0_INTR_SOURCE ETS_I2S1_INTR_SOURCE +# define CLK_SRC I2S_CLK_SRC_PLL_160M +#endif + +#ifdef CONFIG_ESPRESSIF_ESP32C3 +# define GDMA_OUT_TOTAL_EOF_CH0_INT_ENA DMA_OUT_TOTAL_EOF_CH0_INT_ENA +# define GDMA_OUT_DSCR_ERR_CH0_INT_ENA DMA_OUT_DSCR_ERR_CH0_INT_ENA +# define GDMA_IN_SUC_EOF_CH0_INT_ENA DMA_IN_SUC_EOF_CH0_INT_ENA +# define GDMA_OUT_EOF_CH0_INT_ENA DMA_OUT_EOF_CH0_INT_ENA +# define GDMA_OUT_TOTAL_EOF_CH0_INT_ST DMA_OUT_TOTAL_EOF_CH0_INT_ST +# define GDMA_IN_SUC_EOF_CH0_INT_ST DMA_IN_SUC_EOF_CH0_INT_ST +# define CLK_SRC I2S_CLK_SRC_PLL_160M +#endif + +#ifdef CONFIG_ESPRESSIF_ESP32H2 +# define CLK_SRC I2S_CLK_SRC_PLL_64M +#endif + +#ifdef CONFIG_ESPRESSIF_I2S0_DATA_BIT_WIDTH_8BIT +# define ESPRESSIF_I2S0_DATA_BIT_WIDTH 8 +#elif CONFIG_ESPRESSIF_I2S0_DATA_BIT_WIDTH_16BIT +# define ESPRESSIF_I2S0_DATA_BIT_WIDTH 16 +#elif CONFIG_ESPRESSIF_I2S0_DATA_BIT_WIDTH_24BIT +# define ESPRESSIF_I2S0_DATA_BIT_WIDTH 24 +#elif CONFIG_ESPRESSIF_I2S0_DATA_BIT_WIDTH_32BIT +# define ESPRESSIF_I2S0_DATA_BIT_WIDTH 32 +#endif + +/* I2S DMA RX/TX description number */ + +#define I2S_DMADESC_NUM (CONFIG_I2S_DMADESC_NUM) + +/* I2S DMA channel number */ + +#define I2S_DMA_CHANNEL_MAX (2) + +#ifdef CONFIG_ESPRESSIF_I2S0_TX +# define I2S0_TX_ENABLED 1 +# define I2S_HAVE_TX 1 +#else +# define I2S0_TX_ENABLED 0 +#endif + +#ifdef CONFIG_ESPRESSIF_I2S0_RX +# define I2S0_RX_ENABLED 1 +# define I2S_HAVE_RX 1 +#else +# define I2S0_RX_ENABLED 0 +#endif + +/* Debug ********************************************************************/ + +#ifdef CONFIG_DEBUG_I2S_INFO +# define CONFIG_ESPRESSIF_I2S_DUMPBUFFERS +#else +# undef CONFIG_ESPRESSIF_I2S_DUMPBUFFERS +#endif + +#define I2S_GPIO_UNUSED -1 /* For signals which are not used */ + +#define I2S_TDM_AUTO_SLOT_NUM (0) +#define I2S_TDM_AUTO_WS_WIDTH (0) +#define I2S_TDM_AUTO_SLOT (I2S_TDM_SLOT0 | I2S_TDM_SLOT1) + +#define I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(cfg, bits_per_sample, mask) \ + cfg.slot_mask = (mask), \ + cfg.ws_width = I2S_TDM_AUTO_WS_WIDTH, \ + cfg.ws_pol = false, \ + cfg.bit_shift = true, \ + cfg.left_align = false, \ + cfg.big_endian = false, \ + cfg.bit_order_lsb = false, \ + cfg.skip_mask = false, \ + cfg.total_slot = I2S_TDM_AUTO_SLOT_NUM \ + +#define I2S_TDM_MSB_SLOT_DEFAULT_CONFIG(cfg, bits_per_sample, mask) \ + cfg.slot_mask = (mask), \ + cfg.ws_width = I2S_TDM_AUTO_WS_WIDTH, \ + cfg.ws_pol = false, \ + cfg.bit_shift = false, \ + cfg.left_align = false, \ + cfg.big_endian = false, \ + cfg.bit_order_lsb = false, \ + cfg.skip_mask = false , \ + cfg.total_slot = I2S_TDM_AUTO_SLOT_NUM \ + +#define I2S_TDM_PCM_SHORT_SLOT_DEFAULT_CONFIG(cfg, bits_per_sample, mask) \ + cfg.slot_mask = (mask), \ + cfg.ws_width = 1, \ + cfg.ws_pol = true, \ + cfg.bit_shift = true, \ + cfg.left_align = false, \ + cfg.big_endian = false, \ + cfg.bit_order_lsb = false, \ + cfg.skip_mask = false, \ + cfg.total_slot = I2S_TDM_AUTO_SLOT_NUM \ + +#define I2S_PDM_TX_SLOT_DEFAULT_CONFIG(cfg) \ + cfg.sd_prescale = 0, \ + cfg.sd_scale = I2S_PDM_SIG_SCALING_MUL_1, \ + cfg.hp_scale = I2S_PDM_SIG_SCALING_DIV_2, \ + cfg.lp_scale = I2S_PDM_SIG_SCALING_MUL_1, \ + cfg.sinc_scale = I2S_PDM_SIG_SCALING_MUL_1, \ + cfg.line_mode = I2S_PDM_TX_ONE_LINE_CODEC, \ + cfg.hp_en = true, \ + cfg.hp_cut_off_freq_hz = 35.5, \ + cfg.sd_dither = 0, \ + cfg.sd_dither2 = 1 \ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Multiplier of MCLK to sample rate */ + +typedef enum +{ + I2S_MCLK_MULTIPLE_128 = 128, /* mclk = sample_rate * 128 */ + I2S_MCLK_MULTIPLE_256 = 256, /* mclk = sample_rate * 256 */ + I2S_MCLK_MULTIPLE_384 = 384, /* mclk = sample_rate * 384 */ + I2S_MCLK_MULTIPLE_512 = 512, /* mclk = sample_rate * 512 */ +} i2s_mclk_multiple_t; + +/* I2S Audio Standard Mode */ + +typedef enum +{ + I2S_TDM_PHILIPS = 0, + I2S_TDM_MSB, + I2S_TDM_PCM, + I2S_PDM, +} i2s_audio_mode_t; + +/* I2S Device hardware configuration */ + +struct esp_i2s_config_s +{ + uint32_t port; /* I2S port */ + uint32_t role; /* I2S port role (master or slave) */ + uint8_t data_width; /* I2S sample data width */ + uint32_t rate; /* I2S sample-rate */ + uint32_t total_slot; /* Total slot number */ + + bool tx_en; /* Is TX enabled? */ + bool rx_en; /* Is RX enabled? */ + int8_t mclk_pin; /* MCLK pin, output */ + + int tx_clk_src; /* Select the I2S TX source clock */ + int rx_clk_src; /* Select the I2S TX source clock */ + + /* BCLK pin, input in slave role, output in master role */ + + int8_t bclk_pin; + + /* WS pin, input in slave role, output in master role */ + + int8_t ws_pin; + + int8_t dout_pin; /* DATA pin, output */ + int8_t din_pin; /* DATA pin, input */ + + uint32_t bclk_in_insig; /* RX channel BCK signal (slave mode) index */ + uint32_t bclk_in_outsig; /* RX channel BCK signal (master mode) index */ + uint32_t bclk_out_insig; /* TX channel BCK signal (slave mode) index */ + uint32_t bclk_out_outsig; /* TX channel BCK signal (master mode) index */ + uint32_t ws_in_insig; /* RX channel WS signal (slave mode) index */ + uint32_t ws_in_outsig; /* RX channel WS signal (master mode) index */ + uint32_t ws_out_insig; /* TX channel WS signal (slave mode) index */ + uint32_t ws_out_outsig; /* TX channel WS signal (master mode) index */ + uint32_t din_insig; /* RX channel Data Input signal index */ + uint32_t dout_outsig; /* TX channel Data Output signal index */ + uint32_t mclk_out_sig; /* Master clock output index */ + + uint8_t audio_std_mode; /* Select audio standard (i2s_audio_mode_t) */ + + /* WS signal polarity, set true to enable high level first */ + + bool ws_pol; + + i2s_hal_context_t *ctx; /* Common layer struct */ + i2s_hal_clock_info_t *clk_info; /* Common layer clock info struct */ +}; + +struct esp_buffer_s +{ + struct esp_buffer_s *flink; /* Supports a singly linked list */ + + /* The associated DMA in/outlink */ + + struct esp_dmadesc_s dma_link[I2S_DMADESC_NUM]; + + i2s_callback_t callback; /* DMA completion callback */ + uint32_t timeout; /* Timeout value of the DMA transfers */ + void *arg; /* Callback's argument */ + struct ap_buffer_s *apb; /* The audio buffer */ + uint8_t *buf; /* The DMA's descriptor buffer */ + uint32_t nbytes; /* The DMA's descriptor buffer size */ + int result; /* The result of the transfer */ +}; + +/* Internal buffer must be aligned to the bytes_per_sample. Sometimes, + * however, the audio buffer is not aligned and additional bytes must + * be copied to be inserted on the next buffer. This structure keeps + * track of the bytes that were not written to the internal buffer yet. + */ + +struct esp_buffer_carry_s +{ + uint32_t value; + size_t bytes; +}; + +/* This structure describes the state of one receiver or transmitter + * transport. + */ + +struct esp_transport_s +{ + sq_queue_t pend; /* A queue of pending transfers */ + sq_queue_t act; /* A queue of active transfers */ + sq_queue_t done; /* A queue of completed transfers */ + struct work_s work; /* Supports worker thread operations */ + + /* Bytes to be written at the beginning of the next DMA buffer */ + + struct esp_buffer_carry_s carry; +}; + +/* The state of the one I2S peripheral */ + +struct esp_i2s_s +{ + struct i2s_dev_s dev; /* Externally visible I2S interface */ + mutex_t lock; /* Ensures mutually exclusive access */ + uint8_t cpu; /* CPU ID */ + spinlock_t slock; /* Device specific lock. */ + + /* Port configuration */ + + const struct esp_i2s_config_s *config; + + uint32_t mclk_freq; /* I2S actual master clock */ + uint32_t mclk_multiple; /* The multiple of mclk to the sample rate */ + uint32_t channels; /* Audio channels (1:mono or 2:stereo) */ + uint32_t rate; /* I2S actual configured sample-rate */ + uint32_t data_width; /* I2S actual configured data_width */ + uint32_t dma_channel; /* I2S DMA channel being used */ + +#ifdef I2S_HAVE_TX + struct esp_transport_s tx; /* TX transport state */ + + int tx_irq; /* TX IRQ */ + bool tx_started; /* TX channel started */ +#endif /* I2S_HAVE_TX */ + +#ifdef I2S_HAVE_RX + struct esp_transport_s rx; /* RX transport state */ + + int rx_irq; /* RX IRQ */ + bool rx_started; /* RX channel started */ +#endif /* I2S_HAVE_RX */ + + bool streaming; /* Is I2S peripheral active? */ + + /* Pre-allocated pool of buffer containers */ + + sem_t bufsem; /* Buffer wait semaphore */ + struct esp_buffer_s *bf_freelist; /* A list a free buffer containers */ + struct esp_buffer_s containers[CONFIG_ESPRESSIF_I2S_MAXINFLIGHT]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Register helpers */ + +#ifdef CONFIG_ESPRESSIF_I2S_DUMPBUFFERS +# define i2s_dump_buffer(m,b,s) lib_dumpbuffer(m,b,s) +#else +# define i2s_dump_buffer(m,b,s) +#endif + +/* Buffer container helpers */ + +static struct esp_buffer_s * + i2s_buf_allocate(struct esp_i2s_s *priv); +static void i2s_buf_free(struct esp_i2s_s *priv, + struct esp_buffer_s *bfcontainer); +static int i2s_buf_initialize(struct esp_i2s_s *priv); + +/* DMA support */ + +#ifdef I2S_HAVE_TX +static IRAM_ATTR int i2s_txdma_setup(struct esp_i2s_s *priv, + struct esp_buffer_s *bfcontainer); +static void i2s_tx_worker(void *arg); +static void i2s_tx_schedule(struct esp_i2s_s *priv, + struct esp_dmadesc_s *outlink); +#endif /* I2S_HAVE_TX */ + +#ifdef I2S_HAVE_RX +static IRAM_ATTR int i2s_rxdma_setup(struct esp_i2s_s *priv, + struct esp_buffer_s *bfcontainer); +static void i2s_rx_worker(void *arg); +static void i2s_rx_schedule(struct esp_i2s_s *priv, + struct esp_dmadesc_s *outlink); +#endif /* I2S_HAVE_RX */ + +/* I2S methods (and close friends) */ + +static int32_t i2s_check_mclkfrequency(struct esp_i2s_s *priv); +static uint32_t i2s_set_datawidth(struct esp_i2s_s *priv); +static void i2s_set_clock(struct esp_i2s_s *priv); +static uint32_t i2s_getmclkfrequency(struct i2s_dev_s *dev); +static uint32_t i2s_setmclkfrequency(struct i2s_dev_s *dev, + uint32_t frequency); +static int i2s_ioctl(struct i2s_dev_s *dev, int cmd, unsigned long arg); + +#ifdef I2S_HAVE_TX +static void i2s_tx_channel_start(struct esp_i2s_s *priv); +static void i2s_tx_channel_stop(struct esp_i2s_s *priv); +static int i2s_txchannels(struct i2s_dev_s *dev, uint8_t channels); +static uint32_t i2s_txsamplerate(struct i2s_dev_s *dev, uint32_t rate); +static uint32_t i2s_txdatawidth(struct i2s_dev_s *dev, int bits); +static int i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb, + i2s_callback_t callback, void *arg, + uint32_t timeout); +#endif /* I2S_HAVE_TX */ + +#ifdef I2S_HAVE_RX +static void i2s_rx_channel_start(struct esp_i2s_s *priv); +static void i2s_rx_channel_stop(struct esp_i2s_s *priv); +static int i2s_rxchannels(struct i2s_dev_s *dev, uint8_t channels); +static uint32_t i2s_rxsamplerate(struct i2s_dev_s *dev, uint32_t rate); +static uint32_t i2s_rxdatawidth(struct i2s_dev_s *dev, int bits); +static int i2s_receive(struct i2s_dev_s *dev, struct ap_buffer_s *apb, + i2s_callback_t callback, void *arg, + uint32_t timeout); +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct i2s_ops_s g_i2sops = +{ +#ifdef I2S_HAVE_TX + .i2s_txchannels = i2s_txchannels, + .i2s_txsamplerate = i2s_txsamplerate, + .i2s_txdatawidth = i2s_txdatawidth, + .i2s_send = i2s_send, +#endif /* I2S_HAVE_TX */ + +#ifdef I2S_HAVE_RX + .i2s_rxchannels = i2s_rxchannels, + .i2s_rxsamplerate = i2s_rxsamplerate, + .i2s_rxdatawidth = i2s_rxdatawidth, + .i2s_receive = i2s_receive, +#endif /* I2S_HAVE_RX */ + + .i2s_ioctl = i2s_ioctl, + .i2s_getmclkfrequency = i2s_getmclkfrequency, + .i2s_setmclkfrequency = i2s_setmclkfrequency, +}; + +#ifdef CONFIG_ESPRESSIF_I2S0 + +i2s_hal_context_t ctx_i2s0 = +{ + 0 +}; + +i2s_hal_clock_info_t clk_info_i2s0 = +{ + 0 +}; + +static const struct esp_i2s_config_s esp_i2s0_config = +{ + .port = 0, +#ifdef CONFIG_ESPRESSIF_I2S0_ROLE_MASTER + .role = I2S_ROLE_MASTER, +#else + .role = I2S_ROLE_SLAVE, +#endif /* CONFIG_ESPRESSIF_I2S0_ROLE_MASTER */ + .data_width = ESPRESSIF_I2S0_DATA_BIT_WIDTH, + .rate = CONFIG_ESPRESSIF_I2S0_SAMPLE_RATE, + .total_slot = 2, + .tx_en = I2S0_TX_ENABLED, + .rx_en = I2S0_RX_ENABLED, + .tx_clk_src = CLK_SRC, + .rx_clk_src = CLK_SRC, +#ifdef CONFIG_ESPRESSIF_I2S0_MCLK + .mclk_pin = CONFIG_ESPRESSIF_I2S0_MCLKPIN, +#else + .mclk_pin = I2S_GPIO_UNUSED, +#endif /* CONFIG_ESPRESSIF_I2S0_MCLK */ + .bclk_pin = CONFIG_ESPRESSIF_I2S0_BCLKPIN, + .ws_pin = CONFIG_ESPRESSIF_I2S0_WSPIN, +#ifdef CONFIG_ESPRESSIF_I2S0_DOUTPIN + .dout_pin = CONFIG_ESPRESSIF_I2S0_DOUTPIN, +#else + .dout_pin = I2S_GPIO_UNUSED, +#endif /* CONFIG_ESPRESSIF_I2S0_DOUTPIN */ +#ifdef CONFIG_ESPRESSIF_I2S0_DINPIN + .din_pin = CONFIG_ESPRESSIF_I2S0_DINPIN, +#else + .din_pin = I2S_GPIO_UNUSED, +#endif /* CONFIG_ESPRESSIF_I2S0_DINPIN */ + .bclk_in_insig = I2SO_BCK_IN_IDX, + .bclk_in_outsig = I2SO_BCK_OUT_IDX, + .bclk_out_insig = I2SO_BCK_IN_IDX, + .bclk_out_outsig = I2SO_BCK_OUT_IDX, + .ws_in_insig = I2SO_WS_IN_IDX, + .ws_in_outsig = I2SO_WS_OUT_IDX, + .ws_out_insig = I2SO_WS_IN_IDX, + .ws_out_outsig = I2SO_WS_OUT_IDX, + .din_insig = I2SI_SD_IN_IDX, + .dout_outsig = I2SO_SD_OUT_IDX, + .mclk_out_sig = I2S_MCLK_OUT_IDX, + .audio_std_mode = I2S_TDM_PHILIPS, + .ctx = &ctx_i2s0, + .clk_info = &clk_info_i2s0, +}; + +static struct esp_i2s_s esp_i2s0_priv = +{ + .dev = + { + .ops = &g_i2sops, + }, + .lock = NXMUTEX_INITIALIZER, + .config = &esp_i2s0_config, + .bufsem = SEM_INITIALIZER(0), +}; +#endif /* CONFIG_ESPRESSIF_I2S0 */ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: i2s_buf_allocate + * + * Description: + * Allocate a buffer container by removing the one at the head of the + * free list + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * A non-NULL pointer to the allocate buffer container on success; NULL if + * there are no available buffer containers. + * + * Assumptions: + * The caller does NOT have exclusive access to the I2S state structure. + * That would result in a deadlock! + * + ****************************************************************************/ + +static struct esp_buffer_s *i2s_buf_allocate(struct esp_i2s_s *priv) +{ + struct esp_buffer_s *bfcontainer; + irqstate_t flags; + int ret; + + /* Set aside a buffer container. By doing this, we guarantee that we will + * have at least one free buffer container. + */ + + ret = nxsem_wait_uninterruptible(&priv->bufsem); + if (ret < 0) + { + return NULL; + } + + /* Get the buffer from the head of the free list */ + + flags = spin_lock_irqsave(&priv->slock); + bfcontainer = priv->bf_freelist; + DEBUGASSERT(bfcontainer); + + /* Unlink the buffer from the freelist */ + + priv->bf_freelist = bfcontainer->flink; + spin_unlock_irqrestore(&priv->slock, flags); + return bfcontainer; +} + +/**************************************************************************** + * Name: i2s_buf_free + * + * Description: + * Free buffer container by adding it to the head of the free list + * + * Input Parameters: + * priv - Initialized I2S device structure. + * bfcontainer - The buffer container to be freed + * + * Returned Value: + * None + * + * Assumptions: + * The caller has exclusive access to the I2S state structure + * + ****************************************************************************/ + +static void i2s_buf_free(struct esp_i2s_s *priv, + struct esp_buffer_s *bfcontainer) +{ + irqstate_t flags; + + /* Put the buffer container back on the free list (circbuf) */ + + flags = spin_lock_irqsave(&priv->slock); + + bfcontainer->apb = NULL; + bfcontainer->buf = NULL; + bfcontainer->nbytes = 0; + bfcontainer->flink = priv->bf_freelist; + priv->bf_freelist = bfcontainer; + + spin_unlock_irqrestore(&priv->slock, flags); + + /* Wake up any threads waiting for a buffer container */ + + nxsem_post(&priv->bufsem); +} + +/**************************************************************************** + * Name: i2s_buf_initialize + * + * Description: + * Initialize the buffer container allocator by adding all of the + * pre-allocated buffer containers to the free list + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * OK on success; A negated errno value on failure. + * + * Assumptions: + * Called early in I2S initialization so that there are no issues with + * concurrency. + * + ****************************************************************************/ + +static int i2s_buf_initialize(struct esp_i2s_s *priv) +{ +#ifdef I2S_HAVE_TX + priv->tx.carry.bytes = 0; + priv->tx.carry.value = 0; +#endif /* I2S_HAVE_TX */ + + priv->bf_freelist = NULL; + for (int i = 0; i < CONFIG_ESPRESSIF_I2S_MAXINFLIGHT; i++) + { + i2s_buf_free(priv, &priv->containers[i]); + } + + return OK; +} + +/**************************************************************************** + * Name: i2s_txdma_start + * + * Description: + * Initiate the next TX DMA transfer. The DMA outlink was previously bound + * so it is safe to start the next DMA transfer at interrupt level. + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * OK on success; a negated errno value on failure + * + * Assumptions: + * Interrupts are disabled + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static int IRAM_ATTR i2s_txdma_start(struct esp_i2s_s *priv) +{ + struct esp_buffer_s *bfcontainer; + + /* If there is already an active transmission in progress, then bail + * returning success. + */ + + if (!sq_empty(&priv->tx.act)) + { + return OK; + } + + /* If there are no pending transfer, then bail returning success */ + + if (sq_empty(&priv->tx.pend)) + { + return OK; + } + + i2s_hal_tx_reset(priv->config->ctx); + i2s_hal_tx_reset_fifo(priv->config->ctx); + + /* Start transmission if no data is already being transmitted */ + + bfcontainer = (struct esp_buffer_s *)sq_remfirst(&priv->tx.pend); + + esp_dma_load(bfcontainer->dma_link, priv->dma_channel, I2S_DIR_TX); + esp_dma_enable(priv->dma_channel, I2S_DIR_TX); + + i2s_hal_tx_start(priv->config->ctx); + + sq_addlast((sq_entry_t *)bfcontainer, &priv->tx.act); + + return OK; +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rxdma_start + * + * Description: + * Initiate the next RX DMA transfer. Assuming the DMA inlink is already + * bound, it's safe to start the next DMA transfer in an interrupt context. + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * OK on success; a negated errno value on failure + * + * Assumptions: + * Interrupts are disabled + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static int i2s_rxdma_start(struct esp_i2s_s *priv) +{ + struct esp_buffer_s *bfcontainer; + size_t eof_nbytes; + + /* If there is already an active transmission in progress, then bail + * returning success. + */ + + if (!sq_empty(&priv->rx.act)) + { + return OK; + } + + /* If there are no pending transfer, then bail returning success */ + + if (sq_empty(&priv->rx.pend)) + { + return OK; + } + + i2s_hal_rx_reset(priv->config->ctx); + i2s_hal_rx_reset_fifo(priv->config->ctx); + + bfcontainer = (struct esp_buffer_s *)sq_remfirst(&priv->rx.pend); + + /* If there isn't already an active transmission in progress, + * then start it. + */ + + eof_nbytes = MIN(bfcontainer->nbytes, ESPRESSIF_DMA_BUFLEN_MAX); + + i2s_ll_rx_set_eof_num(priv->config->ctx->dev, eof_nbytes); + + esp_dma_load(bfcontainer->dma_link, priv->dma_channel, I2S_DIR_RX); + esp_dma_enable(priv->dma_channel, I2S_DIR_RX); + + i2s_hal_rx_start(priv->config->ctx); + + sq_addlast((sq_entry_t *)bfcontainer, &priv->rx.act); + + return OK; +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_txdma_setup + * + * Description: + * Setup the next TX DMA transfer + * + * Input Parameters: + * priv - Initialized I2S device structure. + * bfcontainer - The buffer container to be set up + * + * Returned Value: + * OK on success; a negated errno value on failure + * + * Assumptions: + * Interrupts are disabled + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static IRAM_ATTR int i2s_txdma_setup(struct esp_i2s_s *priv, + struct esp_buffer_s *bfcontainer) +{ + int ret = OK; + size_t carry_size; + uint32_t bytes_queued; + uint32_t data_copied; + struct ap_buffer_s *apb; + struct esp_dmadesc_s *outlink; + apb_samp_t samp_size; + irqstate_t flags; + uint8_t *buf; + uint8_t padding; + uint8_t *samp; + + DEBUGASSERT(bfcontainer && bfcontainer->apb); + + apb = bfcontainer->apb; + outlink = bfcontainer->dma_link; + + /* Get the transfer information, accounting for any data offset */ + + const apb_samp_t bytes_per_sample = priv->data_width / 8; + samp = &apb->samp[apb->curbyte]; + samp_size = (apb->nbytes - apb->curbyte) + priv->tx.carry.bytes; + carry_size = samp_size % bytes_per_sample; + + /* Allocate the current audio buffer considering the remaining bytes + * carried from the last upper half audio buffer. + */ + + bfcontainer->buf = calloc(bfcontainer->nbytes, 1); + if (bfcontainer->buf == NULL) + { + i2serr("Failed to allocate the DMA internal buffer " + "[%" PRIu32 " bytes]", bfcontainer->nbytes); + return -ENOMEM; + } + + data_copied = 0; + buf = bfcontainer->buf; + + /* Copy the remaining bytes from the last audio buffer to the current + * audio buffer. The remaining bytes are part of a sample that was split + * between the last and the current audio buffer. Also, copy the bytes + * from that split sample that are on the current buffer to the internal + * buffer. + */ + + if (priv->tx.carry.bytes) + { + memcpy(buf, &priv->tx.carry.value, priv->tx.carry.bytes); + buf += priv->tx.carry.bytes; + data_copied += priv->tx.carry.bytes; + memcpy(buf, samp, (bytes_per_sample - priv->tx.carry.bytes)); + buf += (bytes_per_sample - priv->tx.carry.bytes); + samp += (bytes_per_sample - priv->tx.carry.bytes); + data_copied += (bytes_per_sample - priv->tx.carry.bytes); + } + + /* Copy the upper half buffer to the internal buffer considering that + * the current upper half buffer may not contain a complete sample at + * the end of the buffer (and those bytes needs to be carried to the + * next audio buffer). + */ + + memcpy(buf, samp, samp_size - (data_copied + carry_size)); + buf += samp_size - (data_copied + carry_size); + samp += samp_size - (data_copied + carry_size); + data_copied += samp_size - (data_copied + carry_size); + + /* If the audio buffer's size is not a multiple of the sample size, + * it's necessary to carry the remaining bytes that are part of what + * would be the last sample on this buffer. These bytes will then be + * saved and inserted at the beginning of the next DMA buffer to + * rebuild the sample correctly. + */ + + priv->tx.carry.bytes = carry_size; + if (priv->tx.carry.bytes) + { + memcpy((uint8_t *)&priv->tx.carry.value, samp, priv->tx.carry.bytes); + } + + /* Release our reference on the audio buffer. This may very likely + * cause the audio buffer to be freed. + */ + + apb_free(bfcontainer->apb); + + /* Configure DMA stream */ + + bytes_queued = esp_dma_setup(priv->dma_channel, + true, + (struct esp_dmadesc_s *)outlink, + I2S_DMADESC_NUM, + (uint8_t *) bfcontainer->buf, + bfcontainer->nbytes); + + if (bytes_queued != bfcontainer->nbytes) + { + i2serr("Failed to enqueue I2S buffer " + "(%" PRIu32 " bytes of %" PRIu32 ")\n", + bytes_queued, bfcontainer->nbytes); + return -bytes_queued; + } + + flags = spin_lock_irqsave(&priv->slock); + + /* Add the buffer container to the end of the TX pending queue */ + + sq_addlast((sq_entry_t *)bfcontainer, &priv->tx.pend); + + /* Trigger DMA transfer if no transmission is in progress */ + + ret = i2s_txdma_start(priv); + + spin_unlock_irqrestore(&priv->slock, flags); + + return ret; +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rxdma_setup + * + * Description: + * Setup the next RX DMA transfer + * + * Input Parameters: + * priv - Initialized I2S device structure. + * bfcontainer - The buffer container to be set up + * + * Returned Value: + * OK on success; a negated errno value on failure + * + * Assumptions: + * Interrupts are disabled + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static int i2s_rxdma_setup(struct esp_i2s_s *priv, + struct esp_buffer_s *bfcontainer) +{ + int ret = OK; + struct esp_dmadesc_s *inlink; + uint32_t bytes_queued; + irqstate_t flags; + + DEBUGASSERT(bfcontainer && bfcontainer->apb); + + inlink = bfcontainer->dma_link; + + /* Configure DMA stream */ + + bytes_queued = esp_dma_setup(priv->dma_channel, + false, + inlink, + I2S_DMADESC_NUM, + bfcontainer->apb->samp, + bfcontainer->nbytes); + + if (bytes_queued != bfcontainer->nbytes) + { + i2serr("Failed to enqueue I2S buffer " + "(%" PRIu32 " bytes of %" PRIu32 ")\n", + bytes_queued, bfcontainer->nbytes); + return -bytes_queued; + } + + flags = spin_lock_irqsave(&priv->slock); + + /* Add the buffer container to the end of the RX pending queue */ + + sq_addlast((sq_entry_t *)bfcontainer, &priv->rx.pend); + + /* Trigger DMA transfer if no transmission is in progress */ + + ret = i2s_rxdma_start(priv); + + spin_unlock_irqrestore(&priv->slock, flags); + + return ret; +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_tx_schedule + * + * Description: + * An TX DMA completion has occurred. Schedule processing on + * the working thread. + * + * Input Parameters: + * priv - Initialized I2S device structure. + * outlink - DMA outlink descriptor that triggered the interrupt. + * + * Returned Value: + * None + * + * Assumptions: + * - Interrupts are disabled + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static void IRAM_ATTR i2s_tx_schedule(struct esp_i2s_s *priv, + struct esp_dmadesc_s *outlink) +{ + struct esp_buffer_s *bfcontainer; + struct esp_dmadesc_s *bfdesc; + dma_descriptor_t *bfdesc_ctrl; + int ret; + + /* Upon entry, the transfer(s) that just completed are the ones in the + * priv->tx.act queue. + */ + + /* Move all entries from the tx.act queue to the tx.done queue */ + + if (!sq_empty(&priv->tx.act)) + { + /* Remove the next buffer container from the tx.act list */ + + bfcontainer = (struct esp_buffer_s *)sq_peek(&priv->tx.act); + + /* Check if the DMA descriptor that generated an EOF interrupt is the + * last descriptor of the current buffer container's DMA outlink. + * REVISIT: what to do if we miss syncronization and the descriptor + * that generated the interrupt is different from the expected (the + * oldest of the list containing active transmissions)? + */ + + /* Find the last descriptor of the current buffer container */ + + bfdesc = bfcontainer->dma_link; + bfdesc_ctrl = (dma_descriptor_t *)bfdesc; + while (!(bfdesc_ctrl->dw0.suc_eof)) + { + DEBUGASSERT(bfdesc->next); + bfdesc = bfdesc->next; + } + + if (bfdesc == outlink) + { + sq_remfirst(&priv->tx.act); + + /* Report the result of the transfer */ + + bfcontainer->result = OK; + + /* Add the completed buffer container to the tail of the tx.done + * queue + */ + + sq_addlast((sq_entry_t *)bfcontainer, &priv->tx.done); + + /* Check if the DMA is IDLE */ + + if (sq_empty(&priv->tx.act)) + { + /* Then start the next DMA. */ + + i2s_txdma_start(priv); + } + } + + /* If the worker has completed running, then reschedule the working + * thread. + */ + + if (work_available(&priv->tx.work)) + { + /* Schedule the TX DMA done processing to occur on the worker + * thread. + */ + + ret = work_queue(HPWORK, &priv->tx.work, i2s_tx_worker, priv, 0); + if (ret != 0) + { + i2serr("ERROR: Failed to queue TX work: %d\n", ret); + } + } + } +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rx_schedule + * + * Description: + * An RX DMA completion has occurred. Schedule processing on + * the working thread. + * + * Input Parameters: + * priv - Initialized I2S device structure. + * inlink - DMA inlink descriptor that triggered the interrupt. + * + * Returned Value: + * None + * + * Assumptions: + * - Interrupts are disabled + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static void i2s_rx_schedule(struct esp_i2s_s *priv, + struct esp_dmadesc_s *inlink) +{ + struct esp_buffer_s *bfcontainer; + struct esp_dmadesc_s *bfdesc; + dma_descriptor_t *bfdesc_ctrl; + int ret; + + /* Upon entry, the transfer(s) that just completed are the ones in the + * priv->rx.act queue. + */ + + /* Move all entries from the rx.act queue to the rx.done queue */ + + if (!sq_empty(&priv->rx.act)) + { + /* Remove the next buffer container from the rx.act list */ + + bfcontainer = (struct esp_buffer_s *)sq_peek(&priv->rx.act); + + /* Find the last descriptor of the current buffer container */ + + bfdesc = bfcontainer->dma_link; + bfdesc_ctrl = (dma_descriptor_t *)bfdesc; + + while (bfdesc->next != NULL && + (bfdesc_ctrl->dw0.suc_eof)) + { + bfdesc = bfdesc->next; + } + + if (bfdesc == inlink) + { + sq_remfirst(&priv->rx.act); + + /* Report the result of the transfer */ + + bfcontainer->result = OK; + + /* Add the completed buffer container to the tail of the rx.done + * queue + */ + + sq_addlast((sq_entry_t *)bfcontainer, &priv->rx.done); + + /* Check if the DMA is IDLE */ + + if (sq_empty(&priv->rx.act)) + { + /* Then start the next DMA. */ + + i2s_rxdma_start(priv); + } + } + + /* If the worker has completed running, then reschedule the working + * thread. + */ + + if (work_available(&priv->rx.work)) + { + /* Schedule the RX DMA done processing to occur on the worker + * thread. + */ + + ret = work_queue(HPWORK, &priv->rx.work, i2s_rx_worker, priv, 0); + if (ret != 0) + { + i2serr("ERROR: Failed to queue RX work: %d\n", ret); + } + } + } +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_tx_worker + * + * Description: + * TX transfer done worker + * + * Input Parameters: + * arg - the I2S device instance cast to void* + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static void i2s_tx_worker(void *arg) +{ + struct esp_i2s_s *priv = (struct esp_i2s_s *)arg; + struct esp_buffer_s *bfcontainer; + irqstate_t flags; + + DEBUGASSERT(priv); + + /* When the transfer was started, the active buffer containers were removed + * from the tx.pend queue and saved in the tx.act queue. We get here when + * the DMA is finished. + * + * In any case, the buffer containers in tx.act will be moved to the end + * of the tx.done queue and tx.act will be emptied before this worker is + * started. + * + */ + + i2sinfo("tx.act.head=%p tx.done.head=%p\n", + priv->tx.act.head, priv->tx.done.head); + + /* Process each buffer in the tx.done queue */ + + while (sq_peek(&priv->tx.done) != NULL) + { + /* Remove the buffer container from the tx.done queue. NOTE that + * interrupts must be disabled to do this because the tx.done queue is + * also modified from the interrupt level. + */ + + flags = spin_lock_irqsave(&priv->slock); + bfcontainer = (struct esp_buffer_s *)sq_remfirst(&priv->tx.done); + spin_unlock_irqrestore(&priv->slock, flags); + + /* Perform the TX transfer done callback */ + + DEBUGASSERT(bfcontainer && bfcontainer->callback); + bfcontainer->callback(&priv->dev, bfcontainer->apb, + bfcontainer->arg, bfcontainer->result); + + /* Release the internal buffer used by the DMA outlink */ + + free(bfcontainer->buf); + + /* And release the buffer container */ + + i2s_buf_free(priv, bfcontainer); + } +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rx_worker + * + * Description: + * RX transfer done worker + * + * Input Parameters: + * arg - the I2S device instance cast to void* + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static void i2s_rx_worker(void *arg) +{ + struct esp_i2s_s *priv = (struct esp_i2s_s *)arg; + struct esp_buffer_s *bfcontainer; + struct esp_dmadesc_s *dmadesc; + dma_descriptor_t *dmadesc_ctrl; + irqstate_t flags; + + DEBUGASSERT(priv); + + /* When the transfer was started, the active buffer containers were removed + * from the rx.pend queue and saved in the rx.act queue. We get here when + * the DMA is finished. + * + * In any case, the buffer containers in rx.act will be moved to the end + * of the rx.done queue and rx.act will be emptied before this worker is + * started. + * + */ + + i2sinfo("rx.act.head=%p rx.done.head=%p\n", + priv->rx.act.head, priv->rx.done.head); + + /* Process each buffer in the rx.done queue */ + + while (sq_peek(&priv->rx.done) != NULL) + { + /* Remove the buffer container from the rx.done queue. NOTE that + * interrupts must be disabled to do this because the rx.done queue is + * also modified from the interrupt level. + */ + + flags = spin_lock_irqsave(&priv->slock); + bfcontainer = (struct esp_buffer_s *)sq_remfirst(&priv->rx.done); + spin_unlock_irqrestore(&priv->slock, flags); + + dmadesc = bfcontainer->dma_link; + dmadesc_ctrl = (dma_descriptor_t *)dmadesc; + + bfcontainer->apb->nbytes = 0; + + while (dmadesc != NULL && (dmadesc_ctrl->dw0.suc_eof)) + { + bfcontainer->apb->nbytes += dmadesc_ctrl->dw0.length; + dmadesc = dmadesc->next; + } + + /* Perform the RX transfer done callback */ + + DEBUGASSERT(bfcontainer && bfcontainer->callback); + + if (priv->streaming == false) + { + bfcontainer->apb->flags |= AUDIO_APB_FINAL; + } + + bfcontainer->callback(&priv->dev, bfcontainer->apb, + bfcontainer->arg, bfcontainer->result); + + /* Release our reference on the audio buffer. This may very likely + * cause the audio buffer to be freed. + */ + + apb_free(bfcontainer->apb); + + /* And release the buffer container */ + + i2s_buf_free(priv, bfcontainer); + } +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_configure + * + * Description: + * Configure I2S + * + * Input Parameters: + * priv - Partially initialized I2S device structure. This function + * will complete the I2S specific portions of the initialization + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void i2s_configure(struct esp_i2s_s *priv) +{ + uint32_t tx_conf = 0; + uint32_t rx_conf = 0; + bool loopback = false; + i2s_hal_slot_config_t tx_slot_cfg = + { + 0 + }; + + i2s_hal_slot_config_t rx_slot_cfg = + { + 0 + }; + + /* Set peripheral clock and clear reset */ + + periph_module_enable(i2s_periph_signal[priv->config->port].module); + + i2s_hal_init(priv->config->ctx, priv->config->port); + i2s_ll_enable_clock(priv->config->ctx->dev); + + /* Configure multiplexed pins as connected on the board */ + + /* Enable TX channel */ + + if (priv->config->dout_pin != I2S_GPIO_UNUSED) + { + /* If TX channel is used, enable the clock source */ + + esp_gpiowrite(priv->config->dout_pin, 1); + esp_configgpio(priv->config->dout_pin, OUTPUT_FUNCTION_2); + esp_gpio_matrix_out(priv->config->dout_pin, + priv->config->dout_outsig, 0, 0); + } + + /* Enable RX channel */ + + if (priv->config->din_pin != I2S_GPIO_UNUSED) + { + /* If RX channel is used, enable the clock source */ + + /* Check for loopback mode */ + + if (priv->config->dout_pin != I2S_GPIO_UNUSED && + priv->config->din_pin == priv->config->dout_pin) + { + esp_configgpio(priv->config->din_pin, + INPUT_FUNCTION_2 | OUTPUT_FUNCTION_2); + esp_gpio_matrix_in(priv->config->din_pin, + priv->config->din_insig, 0); + esp_gpio_matrix_out(priv->config->din_pin, + priv->config->dout_outsig, 0, 0); + } + else + { + esp_configgpio(priv->config->din_pin, INPUT_FUNCTION_2); + esp_gpio_matrix_in(priv->config->din_pin, + priv->config->din_insig, 0); + } + } + + if (priv->config->role == I2S_ROLE_SLAVE) + { + if (priv->config->tx_en && !priv->config->rx_en) + { + /* For "tx + slave" mode, select TX signal index for ws and bck */ + + esp_gpiowrite(priv->config->ws_pin, 1); + esp_configgpio(priv->config->ws_pin, INPUT_FUNCTION_2); + esp_gpio_matrix_in(priv->config->ws_pin, + priv->config->ws_out_insig, 0); + + esp_gpiowrite(priv->config->bclk_pin, 1); + esp_configgpio(priv->config->bclk_pin, INPUT_FUNCTION_2); + esp_gpio_matrix_in(priv->config->bclk_pin, + priv->config->bclk_out_insig, 0); + } + else + { + /* For "tx + rx + slave" or "rx + slave" mode, select RX signal + * index for ws and bck. + */ + + esp_gpiowrite(priv->config->ws_pin, 1); + esp_configgpio(priv->config->ws_pin, INPUT_FUNCTION_2); + esp_gpio_matrix_in(priv->config->ws_pin, + priv->config->ws_in_insig, 0); + + esp_gpiowrite(priv->config->bclk_pin, 1); + esp_configgpio(priv->config->bclk_pin, INPUT_FUNCTION_2); + esp_gpio_matrix_in(priv->config->bclk_pin, + priv->config->bclk_in_insig, 0); + } + } + else + { + /* Considering master role for the I2S port */ + + /* Set MCLK pin */ + + if (priv->config->mclk_pin != I2S_GPIO_UNUSED) + { + i2sinfo("Configuring GPIO%" PRIu8 " to output master clock\n", + priv->config->mclk_pin); + + esp_gpiowrite(priv->config->mclk_pin, 1); + esp_configgpio(priv->config->mclk_pin, OUTPUT_FUNCTION_2); + esp_gpio_matrix_out(priv->config->mclk_pin, + priv->config->mclk_out_sig, 0, 0); + } + + if (priv->config->rx_en && !priv->config->tx_en) + { + /* For "rx + master" mode, select RX signal index for ws and bck */ + + esp_gpiowrite(priv->config->ws_pin, 1); + esp_configgpio(priv->config->ws_pin, OUTPUT_FUNCTION_2); + esp_gpio_matrix_out(priv->config->ws_pin, + priv->config->ws_in_outsig, 0, 0); + + esp_gpiowrite(priv->config->bclk_pin, 1); + esp_configgpio(priv->config->bclk_pin, OUTPUT_FUNCTION_2); + esp_gpio_matrix_out(priv->config->bclk_pin, + priv->config->bclk_in_outsig, 0, 0); + } + else + { + /* For "tx + rx + master" or "tx + master" mode, select TX signal + * index for ws and bck. + */ + + esp_gpiowrite(priv->config->ws_pin, 1); + esp_configgpio(priv->config->ws_pin, OUTPUT_FUNCTION_2); + esp_gpio_matrix_out(priv->config->ws_pin, + priv->config->ws_out_outsig, 0, 0); + + esp_gpiowrite(priv->config->bclk_pin, 1); + esp_configgpio(priv->config->bclk_pin, OUTPUT_FUNCTION_2); + esp_gpio_matrix_out(priv->config->bclk_pin, + priv->config->bclk_out_outsig, 0, 0); + } + } + + /* Share BCLK and WS if in full-duplex mode */ + + if (priv->config->tx_en && priv->config->rx_en) + { + loopback = true; + } + + i2s_ll_share_bck_ws(priv->config->ctx->dev, loopback); + + /* Configure the TX module */ + + if (priv->config->tx_en) + { + if (priv->channels == 1) + { + tx_slot_cfg.slot_mode = I2S_SLOT_MODE_MONO; + } + else + { + tx_slot_cfg.slot_mode = I2S_SLOT_MODE_STEREO; + } + + tx_slot_cfg.data_bit_width = priv->config->data_width; + tx_slot_cfg.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO; + priv->data_width = priv->config->data_width; + + if (priv->config->audio_std_mode <= I2S_TDM_PCM) + { + i2s_ll_tx_enable_std(priv->config->ctx->dev); + + if (priv->config->audio_std_mode == I2S_TDM_PHILIPS) + { + I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(tx_slot_cfg.tdm, + priv->data_width, + I2S_TDM_AUTO_SLOT); + } + else if (priv->config->audio_std_mode == I2S_TDM_MSB) + { + I2S_TDM_MSB_SLOT_DEFAULT_CONFIG(tx_slot_cfg.tdm, + priv->data_width, + I2S_TDM_AUTO_SLOT); + } + else + { + I2S_TDM_PCM_SHORT_SLOT_DEFAULT_CONFIG(tx_slot_cfg.tdm, + priv->data_width, + I2S_TDM_AUTO_SLOT); + } + + i2s_hal_tdm_set_tx_slot(priv->config->ctx, + priv->config->role == I2S_ROLE_SLAVE, + &tx_slot_cfg); + } + else + { + i2s_ll_tx_enable_pdm(priv->config->ctx->dev); + I2S_PDM_TX_SLOT_DEFAULT_CONFIG(tx_slot_cfg.pdm_tx); + i2s_hal_pdm_set_tx_slot(priv->config->ctx, + priv->config->role == I2S_ROLE_SLAVE, + &tx_slot_cfg); + } + + /* The default value for the master clock frequency (MCLK frequency) + * can be set from the sample rate multiplied by a fixed value, known + * as MCLK multiplier. This multiplier, however, should be divisible + * by the number of bytes from a sample, i.e, for 24 bits, the + * multiplier should be divisible by 3. NOTE: the MCLK frequency can + * be adjusted on runtime, so this value remains valid only if the + * upper half does not implement the `i2s_setmclkfrequency` method. + */ + + if (priv->config->data_width == I2S_DATA_BIT_WIDTH_24BIT) + { + priv->mclk_multiple = I2S_MCLK_MULTIPLE_384; + } + else + { + priv->mclk_multiple = I2S_MCLK_MULTIPLE_256; + } + + i2s_setmclkfrequency((struct i2s_dev_s *)priv, (priv->config->rate * + priv->mclk_multiple)); + + priv->rate = priv->config->rate; + i2s_set_clock(priv); + } + + /* Configure the RX module */ + + if (priv->config->rx_en) + { + if (priv->channels == 1) + { + rx_slot_cfg.slot_mode = I2S_SLOT_MODE_MONO; + } + else + { + rx_slot_cfg.slot_mode = I2S_SLOT_MODE_STEREO; + } + + rx_slot_cfg.data_bit_width = priv->config->data_width; + rx_slot_cfg.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO; + + if (priv->config->audio_std_mode <= I2S_TDM_PCM) + { + i2s_ll_rx_enable_std(priv->config->ctx->dev); + + if (priv->config->audio_std_mode == I2S_TDM_PHILIPS) + { + I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(rx_slot_cfg.tdm, + priv->data_width, + I2S_TDM_AUTO_SLOT); + } + else if (priv->config->audio_std_mode == I2S_TDM_MSB) + { + I2S_TDM_MSB_SLOT_DEFAULT_CONFIG(rx_slot_cfg.tdm, + priv->data_width, + I2S_TDM_AUTO_SLOT); + } + else + { + I2S_TDM_PCM_SHORT_SLOT_DEFAULT_CONFIG(tx_slot_cfg.tdm, + priv->data_width, + I2S_TDM_AUTO_SLOT); + } + + i2s_hal_tdm_set_rx_slot(priv->config->ctx, + priv->config->role == I2S_ROLE_SLAVE, + &rx_slot_cfg); + } + else + { + i2serr("Due to the lack of `PDM to PCM` module, \ + PDM RX is not available\n"); + } + + /* The default value for the master clock frequency (MCLK frequency) + * can be set from the sample rate multiplied by a fixed value, known + * as MCLK multiplier. This multiplier, however, should be divisible + * by the number of bytes from a sample, i.e, for 24 bits, the + * multiplier should be divisible by 3. NOTE: the MCLK frequency can + * be adjusted on runtime, so this value remains valid only if the + * upper half does not implement the `i2s_setmclkfrequency` method. + */ + + if (priv->config->data_width == I2S_DATA_BIT_WIDTH_24BIT) + { + priv->mclk_multiple = I2S_MCLK_MULTIPLE_384; + } + else + { + priv->mclk_multiple = I2S_MCLK_MULTIPLE_256; + } + + i2s_setmclkfrequency((struct i2s_dev_s *)priv, (priv->config->rate * + priv->mclk_multiple)); + + priv->rate = priv->config->rate; + i2s_set_clock(priv); + } +} + +/**************************************************************************** + * Name: i2s_check_mclkfrequency + * + * Description: + * Check if MCLK frequency is compatible with the current data width and + * bits/sample set. Master clock should be multiple of the sample rate and + * bclk at the same time. + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * Returns the current master clock or a negated errno value on failure. + * + ****************************************************************************/ + +static int32_t i2s_check_mclkfrequency(struct esp_i2s_s *priv) +{ + uint32_t mclk_freq; + uint32_t mclk_multiple = priv->mclk_multiple; + uint32_t bclk = priv->rate * priv->config->total_slot * priv->data_width; + int i; + + /* If the master clock is divisible by both the sample rate and the bit + * clock, everything is as expected and we can return the current master + * clock frequency. + */ + + if (priv->mclk_freq % priv->rate == 0 && priv->mclk_freq % bclk == 0) + { + priv->mclk_multiple = priv->mclk_freq / priv->rate; + return priv->mclk_freq; + } + + /* Select the lowest multiplier for setting the master clock */ + + for (mclk_multiple = I2S_MCLK_MULTIPLE_128; + mclk_multiple <= I2S_MCLK_MULTIPLE_512; + mclk_multiple += I2S_MCLK_MULTIPLE_128) + { + mclk_freq = priv->rate * mclk_multiple; + if (mclk_freq % priv->rate == 0 && mclk_freq % bclk == 0) + { + priv->mclk_multiple = mclk_multiple; + i2s_setmclkfrequency((struct i2s_dev_s *)priv, mclk_freq); + return priv->mclk_freq; + } + } + + return -EINVAL; +} + +/**************************************************************************** + * Name: i2s_set_datawidth + * + * Description: + * Set the I2S TX/RX data width. + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * Returns the resulting data width + * + ****************************************************************************/ + +static uint32_t i2s_set_datawidth(struct esp_i2s_s *priv) +{ + int width; +#ifdef I2S_HAVE_TX + if (priv->config->tx_en) + { + i2s_ll_tx_set_sample_bit(priv->config->ctx->dev, + priv->data_width, priv->data_width); + i2s_ll_tx_set_half_sample_bit(priv->config->ctx->dev, + priv->data_width); + + if (priv->config->audio_std_mode != I2S_TDM_PCM) + { + width = priv->data_width; + } + else + { + width = 1; + } + + i2s_ll_tx_set_ws_width(priv->config->ctx->dev, width); + } +#endif /* I2S_HAVE_TX */ + +#ifdef I2S_HAVE_RX + if (priv->config->rx_en) + { + i2s_ll_rx_set_sample_bit(priv->config->ctx->dev, + priv->data_width, priv->data_width); + i2s_ll_rx_set_half_sample_bit(priv->config->ctx->dev, + priv->data_width); + + if (priv->config->audio_std_mode != I2S_TDM_PCM) + { + width = priv->data_width; + } + else + { + width = 1; + } + + i2s_ll_rx_set_ws_width(priv->config->ctx->dev, width); + } +#endif /* I2S_HAVE_RX */ + + return priv->data_width; +} + +/**************************************************************************** + * Name: i2s_set_clock + * + * Description: + * Set the I2S TX sample rate by adjusting I2S clock. + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void i2s_set_clock(struct esp_i2s_s *priv) +{ + uint32_t bclk; + uint32_t mclk; + uint32_t sclk; + uint32_t mclk_div; + uint16_t bclk_div; + + sclk = priv->config->tx_clk_src; + + /* fmclk = bck_div * fbclk = fsclk / (mclk_div + b / a) + * mclk_div is the I2S clock divider's integral value + * b is the fraction clock divider's numerator value + * a is the fraction clock divider's denominator value + */ + + if (priv->config->role == I2S_ROLE_MASTER) + { + bclk = priv->rate * priv->config->total_slot * priv->data_width; + mclk = priv->mclk_freq; + bclk_div = mclk / bclk; + } + else + { + /* For slave mode, mclk >= bclk * 8, so fix bclk_div to 2 first */ + + bclk_div = 8; + bclk = priv->rate * priv->config->total_slot * priv->data_width; + mclk = bclk * bclk_div; + } + + /* Calculate the nearest integer value of the I2S clock divider */ + + mclk_div = sclk / mclk; + + i2sinfo("Clock division info: [sclk]%" PRIu32 " Hz [mdiv] %ld " + "[mclk] %" PRIu32 " Hz [bdiv] %d [bclk] %" PRIu32 " Hz\n", + sclk, mclk_div, mclk, bclk_div, bclk); + + priv->config->clk_info->bclk = bclk; + priv->config->clk_info->bclk_div = bclk_div; + priv->config->clk_info->mclk = mclk; + priv->config->clk_info->mclk_div = mclk_div; + priv->config->clk_info->sclk = sclk; + +#ifdef I2S_HAVE_TX + i2s_hal_set_tx_clock(priv->config->ctx, + priv->config->clk_info, + priv->config->tx_clk_src); +#endif /* I2S_HAVE_TX */ + +#ifdef I2S_HAVE_RX + i2s_hal_set_rx_clock(priv->config->ctx, + priv->config->clk_info, + priv->config->rx_clk_src); +#endif /* I2S_HAVE_RX */ +} + +/**************************************************************************** + * Name: i2s_tx_channel_start + * + * Description: + * Start TX channel for the I2S port + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static void i2s_tx_channel_start(struct esp_i2s_s *priv) +{ + if (priv->config->tx_en) + { + if (priv->tx_started) + { + i2swarn("TX channel of port %ld was previously started\n", + priv->config->port); + return; + } + + /* Reset the DMA operation */ + + esp_dma_reset_channel(priv->dma_channel, true); + + /* Reset the TX channel */ + + /* Reset TX FIFO */ + + i2s_hal_tx_reset(priv->config->ctx); + i2s_hal_tx_reset_fifo(priv->config->ctx); + + /* Set I2S_RX_UPDATE bit to update the configs. + * This bit is automatically cleared. + */ + + i2s_hal_tx_start(priv->config->ctx); + + /* Enable DMA interrupt */ + + up_enable_irq(priv->tx_irq); + + esp_dma_enable_interrupt(priv->dma_channel, true, + GDMA_LL_EVENT_TX_TOTAL_EOF | + GDMA_LL_EVENT_TX_DESC_ERROR, + true); + + priv->tx_started = true; + + i2sinfo("Started TX channel of port %ld\n", priv->config->port); + } +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rx_channel_start + * + * Description: + * Start RX channel for the I2S port + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static void i2s_rx_channel_start(struct esp_i2s_s *priv) +{ + if (priv->config->rx_en) + { + if (priv->rx_started) + { + i2swarn("RX channel of port %ld was previously started\n", + priv->config->port); + return; + } + + /* Reset the DMA operation */ + + esp_dma_reset_channel(priv->dma_channel, false); + + /* Reset the RX channel */ + + /* Reset RX FIFO */ + + i2s_hal_rx_reset(priv->config->ctx); + i2s_hal_rx_reset_fifo(priv->config->ctx); + + /* Set I2S_RX_UPDATE bit to update the configs. + * This bit is automatically cleared. + */ + + i2s_hal_rx_start(priv->config->ctx); + + /* Enable DMA interrupt */ + + up_enable_irq(priv->rx_irq); + + esp_dma_enable_interrupt(priv->dma_channel, false, + GDMA_LL_EVENT_RX_SUC_EOF, + true); + + priv->rx_started = true; + + i2sinfo("Started RX channel of port %ld\n", priv->config->port); + } +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_tx_channel_stop + * + * Description: + * Stop TX channel for the I2S port + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static void i2s_tx_channel_stop(struct esp_i2s_s *priv) +{ + if (priv->config->tx_en) + { + if (!priv->tx_started) + { + i2swarn("TX channel of port %ld was previously stopped\n", + priv->config->port); + return; + } + + /* Stop TX channel */ + + i2s_hal_tx_stop(priv->config->ctx); + + /* Stop outlink */ + + esp_dma_disable(priv->dma_channel, true); + + /* Disable DMA interrupt */ + + esp_dma_enable_interrupt(priv->dma_channel, true, + GDMA_LL_EVENT_TX_EOF, false); + + /* Disable DMA operation mode */ + + up_disable_irq(priv->tx_irq); + + priv->tx_started = false; + + i2sinfo("Stopped TX channel of port %ld\n", priv->config->port); + } +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rx_channel_stop + * + * Description: + * Stop RX channel for the I2S port + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static void i2s_rx_channel_stop(struct esp_i2s_s *priv) +{ + if (priv->config->rx_en) + { + if (!priv->rx_started) + { + i2swarn("RX channel of port %ld was previously stopped\n", + priv->config->port); + return; + } + + /* Stop RX channel */ + + i2s_hal_rx_stop(priv->config->ctx); + + /* Stop outlink */ + + esp_dma_disable(priv->dma_channel, false); + + /* Disable DMA interrupt */ + + esp_dma_enable_interrupt(priv->dma_channel, false, + GDMA_LL_EVENT_RX_SUC_EOF, false); + + /* Disable DMA operation mode */ + + up_disable_irq(priv->rx_irq); + + priv->rx_started = false; + + i2sinfo("Stopped RX channel of port %ld\n", priv->config->port); + } +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_tx_interrupt + * + * Description: + * Common I2S DMA interrupt handler + * + * Input Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info + * arg - I2S controller private data + * + * Returned Value: + * Standard interrupt return value. + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static int IRAM_ATTR i2s_tx_interrupt(int irq, void *context, void *arg) +{ + struct esp_i2s_s *priv = (struct esp_i2s_s *)arg; + struct esp_dmadesc_s *cur = NULL; + + uint32_t status = esp_dma_get_interrupt(priv->dma_channel, true); + + esp_dma_clear_interrupt(priv->dma_channel, true, status); + + if (priv->config->tx_en) + { + if (status & GDMA_LL_EVENT_TX_TOTAL_EOF) + { + cur = (struct esp_dmadesc_s *) + esp_dma_get_desc_addr(priv->dma_channel, true); + + /* Schedule completion of the transfer on the worker thread */ + + i2s_tx_schedule(priv, cur); + } + } + + return 0; +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rx_interrupt + * + * Description: + * Common I2S DMA interrupt handler + * + * Input Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info + * arg - I2S controller private data + * + * Returned Value: + * Standard interrupt return value. + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static int i2s_rx_interrupt(int irq, void *context, void *arg) +{ + struct esp_i2s_s *priv = (struct esp_i2s_s *)arg; + struct esp_dmadesc_s *cur = NULL; + + uint32_t status = esp_dma_get_interrupt(priv->dma_channel, false); + + esp_dma_clear_interrupt(priv->dma_channel, false, status); + + if (priv->config->rx_en) + { + if (status & GDMA_LL_EVENT_RX_SUC_EOF) + { + cur = (struct esp_dmadesc_s *) + esp_dma_get_desc_addr(priv->dma_channel, true); + + /* Schedule completion of the transfer on the worker thread */ + + i2s_rx_schedule(priv, cur); + } + } + + return 0; +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_getmclkfrequency + * + * Description: + * Get the current master clock frequency. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Returns the current master clock. + * + ****************************************************************************/ + +static uint32_t i2s_getmclkfrequency(struct i2s_dev_s *dev) +{ + struct esp_i2s_s *priv = (struct esp_i2s_s *)dev; + + return priv->mclk_freq; +} + +/**************************************************************************** + * Name: i2s_setmclkfrequency + * + * Description: + * Set the master clock frequency. Usually, the MCLK is a multiple of the + * sample rate. Most of the audio codecs require setting specific MCLK + * frequency according to the sample rate. + * + * Input Parameters: + * dev - Device-specific state data + * frequency - The I2S master clock's frequency + * + * Returned Value: + * Returns the resulting master clock or a negated errno value on failure. + * + ****************************************************************************/ + +static uint32_t i2s_setmclkfrequency(struct i2s_dev_s *dev, + uint32_t frequency) +{ + struct esp_i2s_s *priv = (struct esp_i2s_s *)dev; + + /* Check if the master clock frequency is beyond the highest possible + * value and return an error. + */ + + if (frequency >= (priv->config->tx_clk_src / 2)) + { + return -EINVAL; + } + + priv->mclk_freq = frequency; + + return frequency; +} + +/**************************************************************************** + * Name: i2s_txchannels + * + * Description: + * Set the I2S TX number of channels. + * + * Input Parameters: + * dev - Device-specific state data + * channels - The I2S numbers of channels + * + * Returned Value: + * OK on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static int i2s_txchannels(struct i2s_dev_s *dev, uint8_t channels) +{ + struct esp_i2s_s *priv = (struct esp_i2s_s *)dev; + uint32_t channels_mask; + bool is_mono = true; + + if (priv->config->tx_en) + { + if (channels != 1 && channels != 2) + { + return -EINVAL; + } + + i2s_tx_channel_stop(priv); + + priv->channels = channels; + + /* Always consider two channels. For mono (1-channel), we set the + * I2S_TX_TDM_CHAN1_EN to 0 and I2S_TX_CHAN_EQUAL to 1 to send out + * the data of the previous channel. + */ + + /* I2S_TX_TDM_TOT_CHAN_NUM = channels - 1 */ + + i2s_ll_tx_set_chan_num(priv->config->ctx->dev, 2); + + channels_mask = I2S_TX_TDM_CHAN0_EN; + if (priv->channels > 1) + { + channels_mask |= I2S_TX_TDM_CHAN0_EN | I2S_TX_TDM_CHAN1_EN; + is_mono = false; + } + + i2s_ll_tx_enable_mono_mode(priv->config->ctx->dev, + is_mono); + + i2s_ll_tx_set_active_chan_mask(priv->config->ctx->dev, channels_mask); + + /* Set I2S_TX_UPDATE bit to update the configs. + * This bit is automatically cleared. + */ + + i2s_tx_channel_start(priv); + + return OK; + } + + return -ENOTTY; +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rxchannels + * + * Description: + * Set the I2S RX number of channels. + * + * Input Parameters: + * dev - Device-specific state data + * channels - The I2S numbers of channels + * + * Returned Value: + * OK on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static int i2s_rxchannels(struct i2s_dev_s *dev, uint8_t channels) +{ + struct esp_i2s_s *priv = (struct esp_i2s_s *)dev; + + if (priv->config->rx_en) + { + if (channels != 1 && channels != 2) + { + return -EINVAL; + } + + priv->channels = channels; + return OK; + } + + return -ENOTTY; +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_txsamplerate + * + * Description: + * Set the I2S TX sample rate. NOTE: This will have no effect if (1) the + * driver does not support an I2S transmitter or if (2) the sample rate is + * driven by the I2S frame clock. This may also have unexpected side- + * effects of the TX sample is coupled with the RX sample rate. + * + * Input Parameters: + * dev - Device-specific state data + * rate - The I2S sample rate in samples (not bits) per second + * + * Returned Value: + * OK on success, ERROR on fail + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static uint32_t i2s_txsamplerate(struct i2s_dev_s *dev, uint32_t rate) +{ + struct esp_i2s_s *priv = (struct esp_i2s_s *)dev; + + if (priv->config->tx_en) + { + i2s_tx_channel_stop(priv); + + priv->rate = rate; + + if (i2s_check_mclkfrequency(priv) < OK) + { + return ERROR; + } + + i2s_set_clock(priv); + + i2s_tx_channel_start(priv); + + return OK; + } + + return ERROR; +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rxsamplerate + * + * Description: + * Set the I2S RX sample rate. + * + * Input Parameters: + * dev - Device-specific state data + * rate - The I2S sample rate in samples (not bits) per second + * + * Returned Value: + * OK on success, ERROR on fail + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static uint32_t i2s_rxsamplerate(struct i2s_dev_s *dev, uint32_t rate) +{ + struct esp_i2s_s *priv = (struct esp_i2s_s *)dev; + + if (priv->config->rx_en) + { + i2s_rx_channel_stop(priv); + + priv->rate = rate; + + if (i2s_check_mclkfrequency(priv) < OK) + { + return ERROR; + } + + i2s_set_clock(priv); + + i2s_rx_channel_start(priv); + + return OK; + } + + return ERROR; +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_txdatawidth + * + * Description: + * Set the I2S TX data width. The TX bitrate is determined by + * sample_rate * data_width. + * + * Input Parameters: + * dev - Device-specific state data + * width - The I2S data with in bits. + * + * Returned Value: + * Returns the resulting data width + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static uint32_t i2s_txdatawidth(struct i2s_dev_s *dev, int bits) +{ + struct esp_i2s_s *priv = (struct esp_i2s_s *)dev; + + if (priv->config->tx_en) + { + i2s_tx_channel_stop(priv); + + priv->data_width = bits; + + i2s_set_datawidth(priv); + + i2s_tx_channel_start(priv); + + return bits; + } + + return 0; +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rxdatawidth + * + * Description: + * Set the I2S RX data width. The RX bitrate is determined by + * sample_rate * data_width. + * + * Input Parameters: + * dev - Device-specific state data + * width - The I2S data with in bits. + * + * Returned Value: + * Returns the resulting data width + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static uint32_t i2s_rxdatawidth(struct i2s_dev_s *dev, int bits) +{ + struct esp_i2s_s *priv = (struct esp_i2s_s *)dev; + + if (priv->config->rx_en) + { + i2s_rx_channel_stop(priv); + + priv->data_width = bits; + + i2s_set_datawidth(priv); + + i2s_rx_channel_start(priv); + + return bits; + } + + return 0; +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_send + * + * Description: + * Send a block of data on I2S. + * + * Input Parameters: + * dev - Device-specific state data + * apb - A pointer to the audio buffer from which to send data + * callback - A user provided callback function that will be called at + * the completion of the transfer. + * arg - An opaque argument that will be provided to the callback + * when the transfer complete + * timeout - The timeout value to use. The transfer will be cancelled + * and an ETIMEDOUT error will be reported if this timeout + * elapsed without completion of the DMA transfer. Units + * are system clock ticks. Zero means no timeout. + * + * Returned Value: + * OK on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static int i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb, + i2s_callback_t callback, void *arg, uint32_t timeout) +{ + struct esp_i2s_s *priv = (struct esp_i2s_s *)dev; + + if (priv->config->tx_en) + { + struct esp_buffer_s *bfcontainer; + int ret = OK; + uint32_t nbytes; + uint32_t nsamp; + + /* Check audio buffer data size from the upper half. If the buffer + * size is not a multiple of the data width, the remaining bytes + * must be sent along with the next audio buffer. + */ + + nbytes = (apb->nbytes - apb->curbyte) + priv->tx.carry.bytes; + + nbytes -= (nbytes % (priv->data_width / 8)); + + if (nbytes > (ESPRESSIF_DMA_BUFLEN_MAX * I2S_DMADESC_NUM)) + { + i2serr("Required buffer size can't fit into DMA outlink " + "(exceeds in %" PRIu32 " bytes). Try to increase the " + "number of the DMA descriptors (CONFIG_I2S_DMADESC_NUM).", + nbytes - (ESPRESSIF_DMA_BUFLEN_MAX * I2S_DMADESC_NUM)); + return -EFBIG; + } + + /* Allocate a buffer container in advance */ + + bfcontainer = i2s_buf_allocate(priv); + if (bfcontainer == NULL) + { + i2serr("Failed to allocate the buffer container"); + return -ENOMEM; + } + + /* Get exclusive access to the I2S driver data */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + goto errout_with_buf; + } + + /* Add a reference to the audio buffer */ + + apb_reference(apb); + + /* Initialize the buffer container structure */ + + bfcontainer->callback = callback; + bfcontainer->timeout = timeout; + bfcontainer->arg = arg; + bfcontainer->apb = apb; + bfcontainer->nbytes = nbytes; + bfcontainer->result = -EBUSY; + + ret = i2s_txdma_setup(priv, bfcontainer); + + if (ret != OK) + { + goto errout_with_buf; + } + + i2sinfo("Queued %d bytes into DMA buffers\n", apb->nbytes); + i2s_dump_buffer("Audio pipeline buffer:", &apb->samp[apb->curbyte], + apb->nbytes - apb->curbyte); + + nxmutex_unlock(&priv->lock); + + return OK; + +errout_with_buf: + nxmutex_unlock(&priv->lock); + i2s_buf_free(priv, bfcontainer); + return ret; + } + + return -ENOTTY; +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_receive + * + * Description: + * Receive a block of data on I2S. + * + * Input Parameters: + * dev - Device-specific state data + * apb - A pointer to the audio buffer in which to receive data + * callback - A user provided callback function that will be called at + * the completion of the transfer. + * arg - An opaque argument that will be provided to the callback + * when the transfer complete + * timeout - The timeout value to use. The transfer will be cancelled + * and an ETIMEDOUT error will be reported if this timeout + * elapsed without completion of the DMA transfer. Units + * are system clock ticks. Zero means no timeout. + * + * Returned Value: + * OK on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static int i2s_receive(struct i2s_dev_s *dev, struct ap_buffer_s *apb, + i2s_callback_t callback, void *arg, uint32_t timeout) +{ + struct esp_i2s_s *priv = (struct esp_i2s_s *)dev; + + if (priv->config->rx_en) + { + struct esp_buffer_s *bfcontainer; + int ret = OK; + uint32_t nbytes; + uint32_t nsamp; + + /* Check max audio buffer data size from the upper half and align the + * receiving buffer according to the data width. + */ + + nbytes = apb->nmaxbytes; + + nbytes -= (nbytes % (priv->data_width / 8)); + + nbytes = MIN(nbytes, ESPRESSIF_DMA_BUFLEN_MAX); + + /* Allocate a buffer container in advance */ + + bfcontainer = i2s_buf_allocate(priv); + if (bfcontainer == NULL) + { + i2serr("Failed to allocate the buffer container"); + return -ENOMEM; + } + + /* Get exclusive access to the I2S driver data */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + goto errout_with_buf; + } + + /* Add a reference to the audio buffer */ + + apb_reference(apb); + + /* Initialize the buffer container structure */ + + bfcontainer->callback = callback; + bfcontainer->timeout = timeout; + bfcontainer->arg = arg; + bfcontainer->apb = apb; + bfcontainer->nbytes = nbytes; + bfcontainer->result = -EBUSY; + + ret = i2s_rxdma_setup(priv, bfcontainer); + + if (ret != OK) + { + goto errout_with_buf; + } + + i2sinfo("Prepared %d bytes to receive DMA buffers\n", apb->nmaxbytes); + i2s_dump_buffer("Recieved Audio pipeline buffer:", + &apb->samp[apb->curbyte], + apb->nbytes - apb->curbyte); + + nxmutex_unlock(&priv->lock); + + return OK; + +errout_with_buf: + nxmutex_unlock(&priv->lock); + i2s_buf_free(priv, bfcontainer); + return ret; + } + + return -ENOTTY; +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_ioctl + * + * Description: + * Implement the lower-half logic ioctl commands + * + * Input parameters: + * dev - A reference to the lower-half I2S driver device + * cmd - The ioctl command + * arg - The argument accompanying the ioctl command + * + * Returned Value: + * OK on success; A negated errno value on failure. + * + ****************************************************************************/ + +static int i2s_ioctl(struct i2s_dev_s *dev, int cmd, unsigned long arg) +{ + struct esp_i2s_s *priv = (struct esp_i2s_s *)dev; + struct audio_buf_desc_s *bufdesc; + int ret = -ENOTTY; + + switch (cmd) + { + /* AUDIOIOC_START - Start the audio stream. + * + * ioctl argument: Audio session + */ + + case AUDIOIOC_START: + { + i2sinfo("AUDIOIOC_START\n"); + + priv->streaming = true; + + ret = OK; + } + break; + + /* AUDIOIOC_STOP - Stop the audio stream. + * + * ioctl argument: Audio session + */ + +#ifndef CONFIG_AUDIO_EXCLUDE_STOP + case AUDIOIOC_STOP: + { + i2sinfo("AUDIOIOC_STOP\n"); + + priv->streaming = false; + + ret = OK; + } + break; +#endif /* CONFIG_AUDIO_EXCLUDE_STOP */ + + /* AUDIOIOC_ALLOCBUFFER - Allocate an audio buffer + * + * ioctl argument: pointer to an audio_buf_desc_s structure + */ + + case AUDIOIOC_ALLOCBUFFER: + { + i2sinfo("AUDIOIOC_ALLOCBUFFER\n"); + + bufdesc = (struct audio_buf_desc_s *) arg; + ret = apb_alloc(bufdesc); + } + break; + + /* AUDIOIOC_FREEBUFFER - Free an audio buffer + * + * ioctl argument: pointer to an audio_buf_desc_s structure + */ + + case AUDIOIOC_FREEBUFFER: + { + i2sinfo("AUDIOIOC_FREEBUFFER\n"); + + bufdesc = (struct audio_buf_desc_s *) arg; + DEBUGASSERT(bufdesc->u.buffer != NULL); + apb_free(bufdesc->u.buffer); + ret = sizeof(struct audio_buf_desc_s); + } + break; + + default: + break; + } + + return ret; +} + +/**************************************************************************** + * Name: i2s_dma_setup + * + * Description: + * Configure the DMA for the I2S peripheral + * + * Input Parameters: + * priv - Partially initialized I2S device structure. This function + * will complete the I2S specific portions of the initialization + * regarding the DMA operation. + * + * Returned Value: + * OK on success; A negated errno value on failure. + * + ****************************************************************************/ + +static int i2s_dma_setup(struct esp_i2s_s *priv) +{ + int ret; + int i2s_dma_dev; + int periph; + + i2s_dma_dev = ESPRESSIF_DMA_PERIPH_I2S; + + /* Request a GDMA channel for the I2S peripheral */ + + esp_dma_init(); + priv->dma_channel = esp_dma_request(i2s_dma_dev, 1, 1, false); + if (priv->dma_channel < 0) + { + i2serr("Failed to allocate GDMA channel\n"); + return ERROR; + } + + /* Set up to receive GDMA interrupts on the current CPU. Each TX/RX channel + * will be assigned to a different CPU interrupt. + */ + + priv->cpu = this_cpu(); + +#ifdef I2S_HAVE_TX + if (priv->config->tx_en) + { + periph = + gdma_periph_signals.groups[priv->dma_channel].pairs[0].tx_irq_id; + int cpuint = esp_setup_irq(periph, 1, + ESP_IRQ_TRIGGER_LEVEL); + if (cpuint < 0) + { + i2serr("Failed to allocate a CPU interrupt.\n"); + return ERROR; + } + + priv->tx_irq = ESP_SOURCE2IRQ(periph); + ret = irq_attach(priv->tx_irq, i2s_tx_interrupt, priv); + if (ret != OK) + { + i2serr("Couldn't attach IRQ to handler.\n"); + esp_teardown_irq(periph, cpuint); + return ret; + } + } +#endif /* I2S_HAVE_TX */ + +#ifdef I2S_HAVE_RX + if (priv->config->rx_en) + { + periph = + gdma_periph_signals.groups[priv->dma_channel].pairs[0].rx_irq_id; + int cpuint = esp_setup_irq(periph, 1, + ESP_IRQ_TRIGGER_LEVEL); + if (cpuint < 0) + { + i2serr("Failed to allocate a CPU interrupt.\n"); + return ERROR; + } + + priv->rx_irq = ESP_SOURCE2IRQ(periph); + ret = irq_attach(priv->rx_irq, i2s_rx_interrupt, priv); + if (ret != OK) + { + i2serr("Couldn't attach IRQ to handler.\n"); + esp_teardown_irq(periph, cpuint); + return ret; + } + } +#endif /* I2S_HAVE_RX */ + + return OK; +} + +/**************************************************************************** + * Name: esp_i2sbus_initialize + * + * Description: + * Initialize the selected I2S port + * + * Input Parameters: + * port - Port number (for hardware that has multiple I2S interfaces) + * + * Returned Value: + * Valid I2S device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct i2s_dev_s *esp_i2sbus_initialize(int port) +{ + int ret; + struct esp_i2s_s *priv = NULL; + irqstate_t flags; + + i2sinfo("port: %d\n", port); + + /* Statically allocated I2S' device strucuture */ + + switch (port) + { +#ifdef CONFIG_ESPRESSIF_I2S0 + case ESPRESSIF_I2S0: + priv = &esp_i2s0_priv; + break; +#endif + default: + return NULL; + } + + /* Allocate buffer containers */ + + ret = i2s_buf_initialize(priv); + if (ret < 0) + { + goto err; + } + + flags = spin_lock_irqsave(&priv->slock); + + i2s_configure(priv); + + ret = i2s_dma_setup(priv); + if (ret < 0) + { + goto err; + } + +#ifdef I2S_HAVE_TX + /* Start TX channel */ + + if (priv->config->tx_en) + { + priv->tx_started = false; + i2s_tx_channel_start(priv); + } +#endif /* I2S_HAVE_TX */ + +#ifdef I2S_HAVE_RX + /* Start RX channel */ + + if (priv->config->rx_en) + { + priv->rx_started = false; + i2s_rx_channel_start(priv); + } +#endif /* I2S_HAVE_RX */ + + spin_unlock_irqrestore(&priv->slock, flags); + + /* Success exit */ + + i2sinfo("I2S%ld was successfully initialized\n", priv->config->port); + + return &priv->dev; + + /* Failure exit */ + +err: + spin_unlock_irqrestore(&priv->slock, flags); + return NULL; +} diff --git a/arch/risc-v/src/common/espressif/esp_i2s.h b/arch/risc-v/src/common/espressif/esp_i2s.h new file mode 100644 index 0000000000000..d1b1d6f172842 --- /dev/null +++ b/arch/risc-v/src/common/espressif/esp_i2s.h @@ -0,0 +1,76 @@ +/**************************************************************************** + * arch/risc-v/src/common/espressif/esp_i2s.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_I2S_H +#define __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_I2S_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +#ifdef CONFIG_ESPRESSIF_I2S + +#define ESPRESSIF_I2S0 0 + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: esp_i2sbus_initialize + * + * Description: + * Initialize the selected I2S port + * + * Input Parameters: + * port - Port number (for hardware that has multiple I2S interfaces) + * + * Returned Value: + * Valid I2S device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct i2s_dev_s *esp_i2sbus_initialize(int port); + +#endif /* CONFIG_ESPRESSIF_I2S */ + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_I2S_H */ diff --git a/arch/risc-v/src/esp32c3/hal_esp32c3.mk b/arch/risc-v/src/esp32c3/hal_esp32c3.mk index 956dfb3b42b21..24408f4fefc57 100644 --- a/arch/risc-v/src/esp32c3/hal_esp32c3.mk +++ b/arch/risc-v/src/esp32c3/hal_esp32c3.mk @@ -133,6 +133,7 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)mmu_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)rmt_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)i2c_hal.c +CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)i2s_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_hal_iram.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)twai_hal.c @@ -149,10 +150,12 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log_noos.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)riscv$(DELIM)interrupt.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)lldesc.c +CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gdma_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)rmt_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)i2c_periph.c +CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)i2s_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)temperature_sensor_periph.c ifeq ($(CONFIG_ESPRESSIF_SIMPLE_BOOT),y) diff --git a/arch/risc-v/src/esp32c6/hal_esp32c6.mk b/arch/risc-v/src/esp32c6/hal_esp32c6.mk index a0e6c8476c64b..78a4981fdc45b 100644 --- a/arch/risc-v/src/esp32c6/hal_esp32c6.mk +++ b/arch/risc-v/src/esp32c6/hal_esp32c6.mk @@ -134,6 +134,7 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)pcnt_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)rmt_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)i2c_hal.c +CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)i2s_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_hal_iram.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)timer_hal.c @@ -155,11 +156,13 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log_noos.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)riscv$(DELIM)interrupt.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)lldesc.c +CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gdma_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)pcnt_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)rmt_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)i2c_periph.c +CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)i2s_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)mcpwm_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)temperature_sensor_periph.c diff --git a/arch/risc-v/src/esp32h2/hal_esp32h2.mk b/arch/risc-v/src/esp32h2/hal_esp32h2.mk index ec7526e175fbe..e4f7150e49529 100644 --- a/arch/risc-v/src/esp32h2/hal_esp32h2.mk +++ b/arch/risc-v/src/esp32h2/hal_esp32h2.mk @@ -121,6 +121,7 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)pcnt_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)rmt_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)i2c_hal.c +CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)i2s_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_hal_iram.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)timer_hal.c @@ -139,11 +140,13 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log_noos.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)riscv$(DELIM)interrupt.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)lldesc.c +CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gdma_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)pcnt_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)rmt_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)i2c_periph.c +CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)i2s_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)mcpwm_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)temperature_sensor_periph.c diff --git a/boards/risc-v/esp32c3/common/include/esp_board_i2s.h b/boards/risc-v/esp32c3/common/include/esp_board_i2s.h new file mode 100644 index 0000000000000..b5d5e33203dc6 --- /dev/null +++ b/boards/risc-v/esp32c3/common/include/esp_board_i2s.h @@ -0,0 +1,76 @@ +/**************************************************************************** + * boards/risc-v/esp32c3/common/include/esp_board_i2s.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_RISCV_ESP32C3_COMMON_INCLUDE_ESP_BOARD_I2S_H +#define __BOARDS_RISCV_ESP32C3_COMMON_INCLUDE_ESP_BOARD_I2S_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: board_i2s_init + * + * Description: + * Configure the I2S driver. + * + * Input Parameters: + * None. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_ESPRESSIF_I2S +int board_i2s_init(void); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_RISCV_ESP32C3_COMMON_INCLUDE_ESP_BOARD_I2S_H */ diff --git a/boards/risc-v/esp32c3/common/src/Make.defs b/boards/risc-v/esp32c3/common/src/Make.defs index 11d6f67de7c42..a6805d033c55d 100644 --- a/boards/risc-v/esp32c3/common/src/Make.defs +++ b/boards/risc-v/esp32c3/common/src/Make.defs @@ -46,6 +46,10 @@ ifeq ($(CONFIG_I2C_DRIVER),y) CSRCS += esp_board_i2c.c endif +ifeq ($(CONFIG_ESPRESSIF_I2S),y) + CSRCS += esp_board_i2s.c +endif + ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y) CSRCS += esp_board_spiflash.c endif diff --git a/boards/risc-v/esp32c3/common/src/esp_board_i2s.c b/boards/risc-v/esp32c3/common/src/esp_board_i2s.c new file mode 100644 index 0000000000000..91014fad1c08f --- /dev/null +++ b/boards/risc-v/esp32c3/common/src/esp_board_i2s.c @@ -0,0 +1,200 @@ +/**************************************************************************** + * boards/risc-v/esp32c3/common/src/esp_board_i2s.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "espressif/esp_i2s.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_i2sdev_initialize + * + * Description: + * This function is called by platform-specific, setup logic to configure + * and register the generic I2S audio driver. This function will register + * the driver as /dev/audio/pcm[x] where x is determined by the I2S port + * number. + * + * Input Parameters: + * port - The I2S port used for the device + * enable_tx - Register device as TX if true + * enable_rx - Register device as RX if true + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int board_i2sdev_initialize(int port, bool enable_tx, bool enable_rx) +{ + struct audio_lowerhalf_s *audio_i2s; + struct i2s_dev_s *i2s; + char devname[8]; + int ret; + + audinfo("Initializing I2S\n"); + + i2s = esp_i2sbus_initialize(port); + +#ifdef CONFIG_AUDIO_I2SCHAR + ret = i2schar_register(i2s, port); + if (ret < 0) + { + aerr("ERROR: i2schar_register failed: %d\n", ret); + return ret; + } +#endif + + if (enable_tx) + { + /* Initialize audio output */ + + audio_i2s = audio_i2s_initialize(i2s, true); + if (audio_i2s == NULL) + { + auderr("ERROR: Failed to initialize I2S audio output\n"); + return -ENODEV; + } + + snprintf(devname, sizeof(devname), "pcm%d", port); + + /* If nxlooper is selected, the playback buffer is not rendered as + * a WAV file. Therefore, PCM decode will fail while processing such + * output buffer. In such a case, we bypass the PCM decode. + */ + +#ifdef CONFIG_SYSTEM_NXLOOPER + ret = audio_register(devname, audio_i2s); +#else + struct audio_lowerhalf_s *pcm; + + pcm = pcm_decode_initialize(audio_i2s); + if (pcm == NULL) + { + auderr("ERROR: Failed create the PCM decoder\n"); + return -ENODEV; + } + + ret = audio_register(devname, pcm); +#endif /* CONFIG_SYSTEM_NXLOOPER */ + + if (ret < 0) + { + auderr("ERROR: Failed to register /dev/%s device: %d\n", + devname, ret); + return ret; + } + } + + if (enable_rx) + { + /* Initialize audio input */ + + audio_i2s = audio_i2s_initialize(i2s, false); + if (audio_i2s == NULL) + { + auderr("ERROR: Failed to initialize I2S audio input\n"); + return -ENODEV; + } + + snprintf(devname, sizeof(devname), "pcm_in%d", port); + + ret = audio_register(devname, audio_i2s); + if (ret < 0) + { + auderr("ERROR: Failed to register /dev/%s device: %d\n", + devname, ret); + return ret; + } + } + + return ret; +} + +/**************************************************************************** + * Name: board_i2s_init + * + * Description: + * Configure the I2S driver. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +int board_i2s_init(void) +{ + int ret = OK; +#if defined(CONFIG_ESPRESSIF_I2S0) + bool i2s_enable_tx; + bool i2s_enable_rx; +#endif + +#ifdef CONFIG_ESPRESSIF_I2S + +#ifdef CONFIG_ESPRESSIF_I2S0_TX + i2s_enable_tx = true; +#else + i2s_enable_tx = false; +#endif /* CONFIG_ESPRESSIF_I2S0_TX */ + +#ifdef CONFIG_ESPRESSIF_I2S0_RX + i2s_enable_rx = true; +#else + i2s_enable_rx = false; +#endif /* CONFIG_ESPRESSIF_I2S0_RX */ + + /* Configure I2S generic audio on I2S0 */ + + ret = board_i2sdev_initialize(ESPRESSIF_I2S0, + i2s_enable_tx, + i2s_enable_rx); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize I2S0 driver: %d\n", ret); + } + +#endif /* CONFIG_ESPRESSIF_I2S */ + + return ret; +} diff --git a/boards/risc-v/esp32c3/esp32c3-generic/configs/i2schar/defconfig b/boards/risc-v/esp32c3/esp32c3-generic/configs/i2schar/defconfig new file mode 100644 index 0000000000000..16e3639970742 --- /dev/null +++ b/boards/risc-v/esp32c3/esp32c3-generic/configs/i2schar/defconfig @@ -0,0 +1,62 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_NDEBUG is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="risc-v" +CONFIG_ARCH_BOARD="esp32c3-generic" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_ESP32C3_GENERIC=y +CONFIG_ARCH_CHIP="esp32c3" +CONFIG_ARCH_CHIP_ESP32C3_GENERIC=y +CONFIG_ARCH_INTERRUPTSTACK=1536 +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_AUDIO=y +CONFIG_AUDIO_I2S=y +CONFIG_AUDIO_I2SCHAR=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_LOOPSPERMSEC=15000 +CONFIG_BUILTIN=y +CONFIG_DRIVERS_AUDIO=y +CONFIG_ESPRESSIF_I2S0=y +CONFIG_ESPRESSIF_I2S0_MCLK=y +CONFIG_EXAMPLES_I2SCHAR=y +CONFIG_EXAMPLES_I2SCHAR_BUFSIZE=1024 +CONFIG_EXAMPLES_I2SCHAR_RX=y +CONFIG_EXAMPLES_I2SCHAR_RXBUFFERS=2 +CONFIG_EXAMPLES_I2SCHAR_RXSTACKSIZE=4096 +CONFIG_EXAMPLES_I2SCHAR_TX=y +CONFIG_EXAMPLES_I2SCHAR_TXBUFFERS=2 +CONFIG_EXAMPLES_I2SCHAR_TXSTACKSIZE=4096 +CONFIG_FS_PROCFS=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=4096 +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBC_PERROR_STDOUT=y +CONFIG_LIBC_STRERROR=y +CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_NSH_STRERROR=y +CONFIG_PREALLOC_TIMERS=0 +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_BACKTRACE=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=29 +CONFIG_START_MONTH=11 +CONFIG_START_YEAR=2019 +CONFIG_SYSTEM_DUMPSTACK=y +CONFIG_SYSTEM_NSH=y +CONFIG_TESTING_GETPRIME=y +CONFIG_TESTING_OSTEST=y +CONFIG_UART0_SERIAL_CONSOLE=y diff --git a/boards/risc-v/esp32c3/esp32c3-generic/src/esp32c3_bringup.c b/boards/risc-v/esp32c3/esp32c3-generic/src/esp32c3_bringup.c index 1f6edcd855c41..b25a9cff6d89f 100644 --- a/boards/risc-v/esp32c3/esp32c3-generic/src/esp32c3_bringup.c +++ b/boards/risc-v/esp32c3/esp32c3-generic/src/esp32c3_bringup.c @@ -73,6 +73,10 @@ # include "esp_board_rmt.h" #endif +#ifdef CONFIG_ESPRESSIF_I2S +# include "esp_board_i2s.h" +#endif + #ifdef CONFIG_ESPRESSIF_SPI # include "espressif/esp_spi.h" # include "esp_board_spidev.h" @@ -317,6 +321,16 @@ int esp_bringup(void) } #endif +#if defined(CONFIG_ESPRESSIF_I2S) + /* Configure I2S peripheral interfaces */ + + ret = board_i2s_init(); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize I2S driver: %d\n", ret); + } +#endif + #if defined(CONFIG_I2C_DRIVER) /* Configure I2C peripheral interfaces */ diff --git a/boards/risc-v/esp32c6/common/include/esp_board_i2s.h b/boards/risc-v/esp32c6/common/include/esp_board_i2s.h new file mode 100644 index 0000000000000..22d78c5d44e5a --- /dev/null +++ b/boards/risc-v/esp32c6/common/include/esp_board_i2s.h @@ -0,0 +1,76 @@ +/**************************************************************************** + * boards/risc-v/esp32c6/common/include/esp_board_i2s.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_RISCV_ESP32C6_COMMON_INCLUDE_ESP_BOARD_I2S_H +#define __BOARDS_RISCV_ESP32C3_COMMON_INCLUDE_ESP_BOARD_I2S_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: board_i2s_init + * + * Description: + * Configure the I2S driver. + * + * Input Parameters: + * None. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_ESPRESSIF_I2S +int board_i2s_init(void); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_RISCV_ESP32C6_COMMON_INCLUDE_ESP_BOARD_I2S_H */ diff --git a/boards/risc-v/esp32c6/common/src/Make.defs b/boards/risc-v/esp32c6/common/src/Make.defs index a74f146ff2963..18efe25006fc8 100644 --- a/boards/risc-v/esp32c6/common/src/Make.defs +++ b/boards/risc-v/esp32c6/common/src/Make.defs @@ -46,6 +46,10 @@ ifeq ($(CONFIG_I2C_DRIVER),y) CSRCS += esp_board_i2c.c endif +ifeq ($(CONFIG_ESPRESSIF_I2S),y) + CSRCS += esp_board_i2s.c +endif + ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y) CSRCS += esp_board_spiflash.c endif diff --git a/boards/risc-v/esp32c6/common/src/esp_board_i2s.c b/boards/risc-v/esp32c6/common/src/esp_board_i2s.c new file mode 100644 index 0000000000000..019ff8fc37cfd --- /dev/null +++ b/boards/risc-v/esp32c6/common/src/esp_board_i2s.c @@ -0,0 +1,200 @@ +/**************************************************************************** + * boards/risc-v/esp32c6/common/src/esp_board_i2s.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "espressif/esp_i2s.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_i2sdev_initialize + * + * Description: + * This function is called by platform-specific, setup logic to configure + * and register the generic I2S audio driver. This function will register + * the driver as /dev/audio/pcm[x] where x is determined by the I2S port + * number. + * + * Input Parameters: + * port - The I2S port used for the device + * enable_tx - Register device as TX if true + * enable_rx - Register device as RX if true + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int board_i2sdev_initialize(int port, bool enable_tx, bool enable_rx) +{ + struct audio_lowerhalf_s *audio_i2s; + struct i2s_dev_s *i2s; + char devname[8]; + int ret; + + audinfo("Initializing I2S\n"); + + i2s = esp_i2sbus_initialize(port); + +#ifdef CONFIG_AUDIO_I2SCHAR + ret = i2schar_register(i2s, port); + if (ret < 0) + { + aerr("ERROR: i2schar_register failed: %d\n", ret); + return ret; + } +#endif + + if (enable_tx) + { + /* Initialize audio output */ + + audio_i2s = audio_i2s_initialize(i2s, true); + if (audio_i2s == NULL) + { + auderr("ERROR: Failed to initialize I2S audio output\n"); + return -ENODEV; + } + + snprintf(devname, sizeof(devname), "pcm%d", port); + + /* If nxlooper is selected, the playback buffer is not rendered as + * a WAV file. Therefore, PCM decode will fail while processing such + * output buffer. In such a case, we bypass the PCM decode. + */ + +#ifdef CONFIG_SYSTEM_NXLOOPER + ret = audio_register(devname, audio_i2s); +#else + struct audio_lowerhalf_s *pcm; + + pcm = pcm_decode_initialize(audio_i2s); + if (pcm == NULL) + { + auderr("ERROR: Failed create the PCM decoder\n"); + return -ENODEV; + } + + ret = audio_register(devname, pcm); +#endif /* CONFIG_SYSTEM_NXLOOPER */ + + if (ret < 0) + { + auderr("ERROR: Failed to register /dev/%s device: %d\n", + devname, ret); + return ret; + } + } + + if (enable_rx) + { + /* Initialize audio input */ + + audio_i2s = audio_i2s_initialize(i2s, false); + if (audio_i2s == NULL) + { + auderr("ERROR: Failed to initialize I2S audio input\n"); + return -ENODEV; + } + + snprintf(devname, sizeof(devname), "pcm_in%d", port); + + ret = audio_register(devname, audio_i2s); + if (ret < 0) + { + auderr("ERROR: Failed to register /dev/%s device: %d\n", + devname, ret); + return ret; + } + } + + return ret; +} + +/**************************************************************************** + * Name: board_i2s_init + * + * Description: + * Configure the I2S driver. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +int board_i2s_init(void) +{ + int ret = OK; +#if defined(CONFIG_ESPRESSIF_I2S0) + bool i2s_enable_tx; + bool i2s_enable_rx; +#endif + +#ifdef CONFIG_ESPRESSIF_I2S + +#ifdef CONFIG_ESPRESSIF_I2S0_TX + i2s_enable_tx = true; +#else + i2s_enable_tx = false; +#endif /* CONFIG_ESPRESSIF_I2S0_TX */ + +#ifdef CONFIG_ESPRESSIF_I2S0_RX + i2s_enable_rx = true; +#else + i2s_enable_rx = false; +#endif /* CONFIG_ESPRESSIF_I2S0_RX */ + + /* Configure I2S generic audio on I2S0 */ + + ret = board_i2sdev_initialize(ESPRESSIF_I2S0, + i2s_enable_tx, + i2s_enable_rx); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize I2S0 driver: %d\n", ret); + } + +#endif /* CONFIG_ESPRESSIF_I2S */ + + return ret; +} diff --git a/boards/risc-v/esp32c6/esp32c6-devkitc/configs/i2schar/defconfig b/boards/risc-v/esp32c6/esp32c6-devkitc/configs/i2schar/defconfig new file mode 100644 index 0000000000000..f52e657c56a6b --- /dev/null +++ b/boards/risc-v/esp32c6/esp32c6-devkitc/configs/i2schar/defconfig @@ -0,0 +1,64 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_NDEBUG is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="risc-v" +CONFIG_ARCH_BOARD="esp32c6-devkitc" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_ESP32C6_DEVKITC=y +CONFIG_ARCH_CHIP="esp32c6" +CONFIG_ARCH_CHIP_ESP32C6=y +CONFIG_ARCH_CHIP_ESP32C6WROOM1=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_AUDIO=y +CONFIG_AUDIO_I2S=y +CONFIG_AUDIO_I2SCHAR=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_LOOPSPERMSEC=15000 +CONFIG_BUILTIN=y +CONFIG_DRIVERS_AUDIO=y +CONFIG_ESPRESSIF_ESP32C6=y +CONFIG_ESPRESSIF_I2S0=y +CONFIG_ESPRESSIF_I2S0_MCLK=y +CONFIG_EXAMPLES_I2SCHAR=y +CONFIG_EXAMPLES_I2SCHAR_BUFSIZE=1024 +CONFIG_EXAMPLES_I2SCHAR_RX=y +CONFIG_EXAMPLES_I2SCHAR_RXBUFFERS=2 +CONFIG_EXAMPLES_I2SCHAR_RXSTACKSIZE=4096 +CONFIG_EXAMPLES_I2SCHAR_TX=y +CONFIG_EXAMPLES_I2SCHAR_TXBUFFERS=2 +CONFIG_EXAMPLES_I2SCHAR_TXSTACKSIZE=4096 +CONFIG_FS_PROCFS=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=4096 +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBC_PERROR_STDOUT=y +CONFIG_LIBC_STRERROR=y +CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_NSH_STRERROR=y +CONFIG_PREALLOC_TIMERS=0 +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_BACKTRACE=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=29 +CONFIG_START_MONTH=11 +CONFIG_START_YEAR=2019 +CONFIG_SYSTEM_DUMPSTACK=y +CONFIG_SYSTEM_NSH=y +CONFIG_TESTING_GETPRIME=y +CONFIG_TESTING_OSTEST=y +CONFIG_UART0_SERIAL_CONSOLE=y diff --git a/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c b/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c index bc5c02c017db6..9b1c43eb98482 100644 --- a/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c +++ b/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c @@ -73,6 +73,10 @@ # include "esp_board_rmt.h" #endif +#ifdef CONFIG_ESPRESSIF_I2S +# include "esp_board_i2s.h" +#endif + #ifdef CONFIG_ESPRESSIF_SPI # include "espressif/esp_spi.h" # include "esp_board_spidev.h" @@ -270,6 +274,16 @@ int esp_bringup(void) } #endif +#if defined(CONFIG_ESPRESSIF_I2S) + /* Configure I2S peripheral interfaces */ + + ret = board_i2s_init(); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize I2S driver: %d\n", ret); + } +#endif + #if defined(CONFIG_I2C_DRIVER) /* Configure I2C peripheral interfaces */ diff --git a/boards/risc-v/esp32c6/esp32c6-devkitm/configs/i2schar/defconfig b/boards/risc-v/esp32c6/esp32c6-devkitm/configs/i2schar/defconfig new file mode 100644 index 0000000000000..9187a835bc1af --- /dev/null +++ b/boards/risc-v/esp32c6/esp32c6-devkitm/configs/i2schar/defconfig @@ -0,0 +1,64 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_NDEBUG is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="risc-v" +CONFIG_ARCH_BOARD="esp32c6-devkitm" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_ESP32C6_DEVKITM=y +CONFIG_ARCH_CHIP="esp32c6" +CONFIG_ARCH_CHIP_ESP32C6=y +CONFIG_ARCH_CHIP_ESP32C6MINI1=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_AUDIO=y +CONFIG_AUDIO_I2S=y +CONFIG_AUDIO_I2SCHAR=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_LOOPSPERMSEC=15000 +CONFIG_BUILTIN=y +CONFIG_DRIVERS_AUDIO=y +CONFIG_ESPRESSIF_ESP32C6=y +CONFIG_ESPRESSIF_I2S0=y +CONFIG_ESPRESSIF_I2S0_MCLK=y +CONFIG_EXAMPLES_I2SCHAR=y +CONFIG_EXAMPLES_I2SCHAR_BUFSIZE=1024 +CONFIG_EXAMPLES_I2SCHAR_RX=y +CONFIG_EXAMPLES_I2SCHAR_RXBUFFERS=2 +CONFIG_EXAMPLES_I2SCHAR_RXSTACKSIZE=4096 +CONFIG_EXAMPLES_I2SCHAR_TX=y +CONFIG_EXAMPLES_I2SCHAR_TXBUFFERS=2 +CONFIG_EXAMPLES_I2SCHAR_TXSTACKSIZE=4096 +CONFIG_FS_PROCFS=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=4096 +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBC_PERROR_STDOUT=y +CONFIG_LIBC_STRERROR=y +CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_NSH_STRERROR=y +CONFIG_PREALLOC_TIMERS=0 +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_BACKTRACE=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=29 +CONFIG_START_MONTH=11 +CONFIG_START_YEAR=2019 +CONFIG_SYSTEM_DUMPSTACK=y +CONFIG_SYSTEM_NSH=y +CONFIG_TESTING_GETPRIME=y +CONFIG_TESTING_OSTEST=y +CONFIG_UART0_SERIAL_CONSOLE=y diff --git a/boards/risc-v/esp32c6/esp32c6-devkitm/src/esp32c6_bringup.c b/boards/risc-v/esp32c6/esp32c6-devkitm/src/esp32c6_bringup.c index ac4a1ac0e3c27..aaa8a84e1a29b 100644 --- a/boards/risc-v/esp32c6/esp32c6-devkitm/src/esp32c6_bringup.c +++ b/boards/risc-v/esp32c6/esp32c6-devkitm/src/esp32c6_bringup.c @@ -73,6 +73,10 @@ # include "esp_board_rmt.h" #endif +#ifdef CONFIG_ESPRESSIF_I2S +# include "esp_board_i2s.h" +#endif + #ifdef CONFIG_ESPRESSIF_SPI # include "espressif/esp_spi.h" # include "esp_board_spidev.h" @@ -266,6 +270,16 @@ int esp_bringup(void) } #endif +#if defined(CONFIG_ESPRESSIF_I2S) + /* Configure I2S peripheral interfaces */ + + ret = board_i2s_init(); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize I2S driver: %d\n", ret); + } +#endif + #if defined(CONFIG_I2C_DRIVER) /* Configure I2C peripheral interfaces */ diff --git a/boards/risc-v/esp32h2/common/include/esp_board_i2s.h b/boards/risc-v/esp32h2/common/include/esp_board_i2s.h new file mode 100644 index 0000000000000..412c5bce7d890 --- /dev/null +++ b/boards/risc-v/esp32h2/common/include/esp_board_i2s.h @@ -0,0 +1,76 @@ +/**************************************************************************** + * boards/risc-v/esp32h2/common/include/esp_board_i2s.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_RISCV_ESP32H2_COMMON_INCLUDE_ESP_BOARD_I2S_H +#define __BOARDS_RISCV_ESP32H2_COMMON_INCLUDE_ESP_BOARD_I2S_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: board_i2s_init + * + * Description: + * Configure the I2S driver. + * + * Input Parameters: + * None. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_ESPRESSIF_I2S +int board_i2s_init(void); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_RISCV_ESP32H2_COMMON_INCLUDE_ESP_BOARD_I2S_H */ diff --git a/boards/risc-v/esp32h2/common/src/Make.defs b/boards/risc-v/esp32h2/common/src/Make.defs index 380d83ab26304..be47fb1424fc6 100644 --- a/boards/risc-v/esp32h2/common/src/Make.defs +++ b/boards/risc-v/esp32h2/common/src/Make.defs @@ -46,6 +46,10 @@ ifeq ($(CONFIG_I2C_DRIVER),y) CSRCS += esp_board_i2c.c endif +ifeq ($(CONFIG_ESPRESSIF_I2S),y) + CSRCS += esp_board_i2s.c +endif + ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y) CSRCS += esp_board_spiflash.c endif diff --git a/boards/risc-v/esp32h2/common/src/esp_board_i2s.c b/boards/risc-v/esp32h2/common/src/esp_board_i2s.c new file mode 100644 index 0000000000000..9cd2e7c7ef7df --- /dev/null +++ b/boards/risc-v/esp32h2/common/src/esp_board_i2s.c @@ -0,0 +1,200 @@ +/**************************************************************************** + * boards/risc-v/esp32h2/common/src/esp_board_i2s.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "espressif/esp_i2s.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_i2sdev_initialize + * + * Description: + * This function is called by platform-specific, setup logic to configure + * and register the generic I2S audio driver. This function will register + * the driver as /dev/audio/pcm[x] where x is determined by the I2S port + * number. + * + * Input Parameters: + * port - The I2S port used for the device + * enable_tx - Register device as TX if true + * enable_rx - Register device as RX if true + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int board_i2sdev_initialize(int port, bool enable_tx, bool enable_rx) +{ + struct audio_lowerhalf_s *audio_i2s; + struct i2s_dev_s *i2s; + char devname[8]; + int ret; + + audinfo("Initializing I2S\n"); + + i2s = esp_i2sbus_initialize(port); + +#ifdef CONFIG_AUDIO_I2SCHAR + ret = i2schar_register(i2s, port); + if (ret < 0) + { + aerr("ERROR: i2schar_register failed: %d\n", ret); + return ret; + } +#endif + + if (enable_tx) + { + /* Initialize audio output */ + + audio_i2s = audio_i2s_initialize(i2s, true); + if (audio_i2s == NULL) + { + auderr("ERROR: Failed to initialize I2S audio output\n"); + return -ENODEV; + } + + snprintf(devname, sizeof(devname), "pcm%d", port); + + /* If nxlooper is selected, the playback buffer is not rendered as + * a WAV file. Therefore, PCM decode will fail while processing such + * output buffer. In such a case, we bypass the PCM decode. + */ + +#ifdef CONFIG_SYSTEM_NXLOOPER + ret = audio_register(devname, audio_i2s); +#else + struct audio_lowerhalf_s *pcm; + + pcm = pcm_decode_initialize(audio_i2s); + if (pcm == NULL) + { + auderr("ERROR: Failed create the PCM decoder\n"); + return -ENODEV; + } + + ret = audio_register(devname, pcm); +#endif /* CONFIG_SYSTEM_NXLOOPER */ + + if (ret < 0) + { + auderr("ERROR: Failed to register /dev/%s device: %d\n", + devname, ret); + return ret; + } + } + + if (enable_rx) + { + /* Initialize audio input */ + + audio_i2s = audio_i2s_initialize(i2s, false); + if (audio_i2s == NULL) + { + auderr("ERROR: Failed to initialize I2S audio input\n"); + return -ENODEV; + } + + snprintf(devname, sizeof(devname), "pcm_in%d", port); + + ret = audio_register(devname, audio_i2s); + if (ret < 0) + { + auderr("ERROR: Failed to register /dev/%s device: %d\n", + devname, ret); + return ret; + } + } + + return ret; +} + +/**************************************************************************** + * Name: board_i2s_init + * + * Description: + * Configure the I2S driver. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +int board_i2s_init(void) +{ + int ret = OK; +#if defined(CONFIG_ESPRESSIF_I2S0) + bool i2s_enable_tx; + bool i2s_enable_rx; +#endif + +#ifdef CONFIG_ESPRESSIF_I2S + +#ifdef CONFIG_ESPRESSIF_I2S0_TX + i2s_enable_tx = true; +#else + i2s_enable_tx = false; +#endif /* CONFIG_ESPRESSIF_I2S0_TX */ + +#ifdef CONFIG_ESPRESSIF_I2S0_RX + i2s_enable_rx = true; +#else + i2s_enable_rx = false; +#endif /* CONFIG_ESPRESSIF_I2S0_RX */ + + /* Configure I2S generic audio on I2S0 */ + + ret = board_i2sdev_initialize(ESPRESSIF_I2S0, + i2s_enable_tx, + i2s_enable_rx); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize I2S0 driver: %d\n", ret); + } + +#endif /* CONFIG_ESPRESSIF_I2S */ + + return ret; +} diff --git a/boards/risc-v/esp32h2/esp32h2-devkit/configs/i2schar/defconfig b/boards/risc-v/esp32h2/esp32h2-devkit/configs/i2schar/defconfig new file mode 100644 index 0000000000000..552d0a6facd9a --- /dev/null +++ b/boards/risc-v/esp32h2/esp32h2-devkit/configs/i2schar/defconfig @@ -0,0 +1,63 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_NDEBUG is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="risc-v" +CONFIG_ARCH_BOARD="esp32h2-devkit" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_ESP32H2_DEVKIT=y +CONFIG_ARCH_CHIP="esp32h2" +CONFIG_ARCH_CHIP_ESP32H2=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_AUDIO=y +CONFIG_AUDIO_I2S=y +CONFIG_AUDIO_I2SCHAR=y +CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_LOOPSPERMSEC=15000 +CONFIG_BUILTIN=y +CONFIG_DRIVERS_AUDIO=y +CONFIG_ESPRESSIF_ESP32H2=y +CONFIG_ESPRESSIF_I2S0=y +CONFIG_ESPRESSIF_I2S0_MCLK=y +CONFIG_EXAMPLES_I2SCHAR=y +CONFIG_EXAMPLES_I2SCHAR_BUFSIZE=1024 +CONFIG_EXAMPLES_I2SCHAR_RX=y +CONFIG_EXAMPLES_I2SCHAR_RXBUFFERS=2 +CONFIG_EXAMPLES_I2SCHAR_RXSTACKSIZE=4096 +CONFIG_EXAMPLES_I2SCHAR_TX=y +CONFIG_EXAMPLES_I2SCHAR_TXBUFFERS=2 +CONFIG_EXAMPLES_I2SCHAR_TXSTACKSIZE=4096 +CONFIG_FS_PROCFS=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=4096 +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBC_PERROR_STDOUT=y +CONFIG_LIBC_STRERROR=y +CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_NSH_STRERROR=y +CONFIG_PREALLOC_TIMERS=0 +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_BACKTRACE=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=29 +CONFIG_START_MONTH=11 +CONFIG_START_YEAR=2019 +CONFIG_SYSTEM_DUMPSTACK=y +CONFIG_SYSTEM_NSH=y +CONFIG_TESTING_GETPRIME=y +CONFIG_TESTING_OSTEST=y +CONFIG_UART0_SERIAL_CONSOLE=y diff --git a/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_bringup.c b/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_bringup.c index cdbcf5102cbc1..6c3fb943c0584 100644 --- a/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_bringup.c +++ b/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_bringup.c @@ -73,6 +73,10 @@ # include "esp_board_rmt.h" #endif +#ifdef CONFIG_ESPRESSIF_I2S +# include "esp_board_i2s.h" +#endif + #ifdef CONFIG_ESPRESSIF_SPI # include "espressif/esp_spi.h" # include "esp_board_spidev.h" @@ -264,6 +268,16 @@ int esp_bringup(void) } #endif +#if defined(CONFIG_ESPRESSIF_I2S) + /* Configure I2S peripheral interfaces */ + + ret = board_i2s_init(); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize I2S driver: %d\n", ret); + } +#endif + #if defined(CONFIG_I2C_DRIVER) /* Configure I2C peripheral interfaces */ From c80e69e5e5ec0c69924e91042301af52a3fa382d Mon Sep 17 00:00:00 2001 From: Eren Terzioglu Date: Mon, 17 Feb 2025 09:39:19 +0100 Subject: [PATCH 16/33] esp32[c3|c6|h2]: Update common layer Update common layer to prevent build errors Signed-off-by: Eren Terzioglu --- arch/risc-v/src/common/espressif/Make.defs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/risc-v/src/common/espressif/Make.defs b/arch/risc-v/src/common/espressif/Make.defs index a5d0ddf76aeb3..d62602887b169 100644 --- a/arch/risc-v/src/common/espressif/Make.defs +++ b/arch/risc-v/src/common/espressif/Make.defs @@ -163,7 +163,7 @@ endif ESP_HAL_3RDPARTY_REPO = esp-hal-3rdparty ifndef ESP_HAL_3RDPARTY_VERSION - ESP_HAL_3RDPARTY_VERSION = 87ccbf88b6fd490dae1993524e70f51bb2ea181d + ESP_HAL_3RDPARTY_VERSION = e23f3131b564068a5033b765017a494c9553ce65 endif ifndef ESP_HAL_3RDPARTY_URL From 9d8a66717c6222e1028f71efca4aa2f4a26f45d3 Mon Sep 17 00:00:00 2001 From: Rodrigo Sim Date: Thu, 20 Feb 2025 11:51:18 -0300 Subject: [PATCH 17/33] Documentation:Fix Seeed Studio XIAO nRF52840 Change XIAO nRF52840 name at Documentation to match product name and other Seeed Studio boards. Signed-off-by: Rodrigo Sim --- .../platforms/arm/nrf52/boards/xiao-nrf52840/index.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/platforms/arm/nrf52/boards/xiao-nrf52840/index.rst b/Documentation/platforms/arm/nrf52/boards/xiao-nrf52840/index.rst index 1f03137a48d67..880efc9579cb2 100644 --- a/Documentation/platforms/arm/nrf52/boards/xiao-nrf52840/index.rst +++ b/Documentation/platforms/arm/nrf52/boards/xiao-nrf52840/index.rst @@ -1,6 +1,6 @@ -============= -XIAO nRF52840 -============= +========================== +Seeed Studio XIAO nRF52840 +========================== The `Seeed Studio XIAO nRF52840 `_ is a general purpose board supplied by Seeed Studio and it is compatible with the Nordic nRF52840 ecosystem as they share the same MCU. From b542be4a14ddb15b25da6ef0c9ec377dbd82d22f Mon Sep 17 00:00:00 2001 From: Filipe Cavalcanti Date: Wed, 19 Feb 2025 13:29:59 -0300 Subject: [PATCH 18/33] drivers/net: change format specifiers macros on lan9250 driver This fixes build warnings when different archs are used. Simply changes "lx" to "PRIx32" when using uint32_t. --- drivers/net/lan9250.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/lan9250.c b/drivers/net/lan9250.c index 8f02fb83ea3fa..f42197ce4ac7a 100644 --- a/drivers/net/lan9250.c +++ b/drivers/net/lan9250.c @@ -617,7 +617,9 @@ static void lan9250_wait_ready(FAR struct lan9250_driver_s *priv, if (timeout) { - nerr("ERROR: wait register:0x%02x, mask:0x%08x, expected:0x%08x\n", + nerr("ERROR: wait register:0x%02" PRIx32 \ + ", mask:0x%08" PRIx32 \ + ", expected:0x%08" PRIx32 "\n", address, mask, expected); } } @@ -734,7 +736,8 @@ static void lan9250_wait_mac_ready(FAR struct lan9250_driver_s *priv, if (timeout) { - nerr("ERROR: wait MAC register:0x%02x, mask:0x%08x, expected:0x%08x\n", + nerr("ERROR: wait MAC register:0x%02" PRIx32 \ + ", mask:0x%08" PRIx32 ", expect:0x%08" PRIx32 "\n", address, mask, expected); } } @@ -1178,11 +1181,11 @@ static int lan9250_reset(FAR struct lan9250_driver_s *priv) regval = lan9250_get_reg(priv, LAN9250_CIARR); if ((regval & CIARR_CID_M) != CIARR_CID_V) { - nerr("ERROR: Bad Rev ID: %08x\n", regval); + nerr("ERROR: Bad Rev ID: %08" PRIx32 "\n", regval); return -ENODEV; } - ninfo("Rev ID: %08x\n", regval & CIARR_CREV_M); + ninfo("Rev ID: %08" PRIx32 "\n", regval & CIARR_CREV_M); /* Configure TX FIFO size mode to be 8: * @@ -1809,7 +1812,7 @@ static void lan9250_int_worker(FAR void *arg) * settings. */ - ninfo("Interrupt status: %08x\n", regval); + ninfo("Interrupt status: %08" PRIx32 "\n", regval); #if LAN9250_INT_SOURCE & IER_SW if ((regval & ISR_SW) != 0) From 798a73ac1a9adbff19dfd87d046c27197f8109bd Mon Sep 17 00:00:00 2001 From: Tiago Medicci Serrano Date: Thu, 20 Feb 2025 11:10:28 -0300 Subject: [PATCH 19/33] Documentation/python: Fix tutorial for running Python After https://github.com/apache/nuttx-apps/pull/2982, there is no need to mount the modules and manually set the required environment variables: they are all set by the new Python wrapper application. Signed-off-by: Tiago Medicci Serrano --- .../applications/interpreters/python/index.rst | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Documentation/applications/interpreters/python/index.rst b/Documentation/applications/interpreters/python/index.rst index f459ed9fa86a0..2fd4966bd32e1 100644 --- a/Documentation/applications/interpreters/python/index.rst +++ b/Documentation/applications/interpreters/python/index.rst @@ -18,10 +18,10 @@ How Does it Work? 1. Python for NuttX target initially the ``rv-virt`` (RISC-V QEMU) board. 2. Python modules are stored in `pyc `_ (byte-code format) and are loaded from a ROMFS image at startup. -3. Environment variables like ``PYTHONHOME`` and ``PYTHON_BASIC_REPL`` need to be set accordingly. +3. The Python wrapper application on NuttX mounts the ROMFS partition which contains the Python modules and sets the required environment variables (``PYTHONHOME`` and ``PYTHON_BASIC_REPL``) automatically. -Building Python NuttX -===================== +Building Python on NuttX +======================== Use the ``rv-virt:python`` config to build Python for NuttX. Note that the CMake scripts don't work for this configuration. For now, please use the makefile build instead: @@ -66,10 +66,6 @@ Then, run RISC-V QEMU with the following command: telnetd [4:100] NuttShell (NSH) NuttX-10.4.0 - nsh> python_mount_modules - Mounting ROMFS filesystem at target=/usr/local/lib/ with source=/dev/ram1 - nsh> export PYTHONHOME /usr/local - nsh> export PYTHON_BASIC_REPL 1 nsh> python Python 3.13.0 (main, Dec 4 2024, 17:00:42) [GCC 13.2.0] on nuttx Type "help", "copyright", "credits" or "license" for more information. From 35a793ed17285ca7495d0c01982f35eb70903c3d Mon Sep 17 00:00:00 2001 From: simbit18 Date: Fri, 21 Feb 2025 12:06:23 +0100 Subject: [PATCH 20/33] [nxstyle] fix Relative files path fix Relative file path does not match actual file. Signed-off-by: simbit18 --- arch/tricore/src/cmake/ToolchainGnuc.cmake | 2 +- arch/tricore/src/cmake/ToolchainTasking.cmake | 2 +- boards/arm/csk6/csk6011a-nano/src/Makefile | 2 +- boards/arm/imx9/imx95-evk/scripts/Make.defs | 2 +- boards/arm/imx9/imx95-evk/src/Makefile | 2 +- libs/libc/machine/x86_64/gnu/CMakeLists.txt | 2 +- libs/libxx/uClibc++/system_configuration.h | 6 +++--- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/tricore/src/cmake/ToolchainGnuc.cmake b/arch/tricore/src/cmake/ToolchainGnuc.cmake index d715bbb7abebe..1469817b3677b 100644 --- a/arch/tricore/src/cmake/ToolchainGnuc.cmake +++ b/arch/tricore/src/cmake/ToolchainGnuc.cmake @@ -1,5 +1,5 @@ # ############################################################################## -# arch/tricore/src/cmake/Toolchain.cmake +# arch/tricore/src/cmake/ToolchainGnuc.cmake # # SPDX-License-Identifier: Apache-2.0 # diff --git a/arch/tricore/src/cmake/ToolchainTasking.cmake b/arch/tricore/src/cmake/ToolchainTasking.cmake index 610fa31bf795c..e035017274fc5 100644 --- a/arch/tricore/src/cmake/ToolchainTasking.cmake +++ b/arch/tricore/src/cmake/ToolchainTasking.cmake @@ -1,5 +1,5 @@ # ############################################################################## -# arch/tricore/src/cmake/Toolchain.cmake +# arch/tricore/src/cmake/ToolchainTasking.cmake # # SPDX-License-Identifier: Apache-2.0 # diff --git a/boards/arm/csk6/csk6011a-nano/src/Makefile b/boards/arm/csk6/csk6011a-nano/src/Makefile index 59ffcb7c34755..ccece7f7ad26a 100644 --- a/boards/arm/csk6/csk6011a-nano/src/Makefile +++ b/boards/arm/csk6/csk6011a-nano/src/Makefile @@ -1,5 +1,5 @@ ############################################################################ -# boards/arm/csk6011a/csk6011a-nano/src/Makefile +# boards/arm/csk6/csk6011a-nano/src/Makefile # # SPDX-License-Identifier: Apache-2.0 # diff --git a/boards/arm/imx9/imx95-evk/scripts/Make.defs b/boards/arm/imx9/imx95-evk/scripts/Make.defs index d4591a9eb92a6..a88c3e0b6b394 100644 --- a/boards/arm/imx9/imx95-evk/scripts/Make.defs +++ b/boards/arm/imx9/imx95-evk/scripts/Make.defs @@ -1,5 +1,5 @@ ############################################################################ -# boards/arm/imx95/imx95-evk/scripts/Make.defs +# boards/arm/imx9/imx95-evk/scripts/Make.defs # # SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: 2024 NXP diff --git a/boards/arm/imx9/imx95-evk/src/Makefile b/boards/arm/imx9/imx95-evk/src/Makefile index 6150390418858..ad36c4085c2c6 100644 --- a/boards/arm/imx9/imx95-evk/src/Makefile +++ b/boards/arm/imx9/imx95-evk/src/Makefile @@ -1,5 +1,5 @@ ############################################################################ -# boards/arm/imx95/imx95-evk/src/Makefile +# boards/arm/imx9/imx95-evk/src/Makefile # # SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: 2024 NXP diff --git a/libs/libc/machine/x86_64/gnu/CMakeLists.txt b/libs/libc/machine/x86_64/gnu/CMakeLists.txt index 9c4ab0431b321..7d0715d9a2d30 100644 --- a/libs/libc/machine/x86_64/gnu/CMakeLists.txt +++ b/libs/libc/machine/x86_64/gnu/CMakeLists.txt @@ -1,5 +1,5 @@ # ############################################################################## -# libs/libc/machine/X86_64/gnu/CMakeLists.txt +# libs/libc/machine/x86_64/gnu/CMakeLists.txt # # SPDX-License-Identifier: Apache-2.0 # diff --git a/libs/libxx/uClibc++/system_configuration.h b/libs/libxx/uClibc++/system_configuration.h index 9f560ff8047d4..11c246dc9ba13 100644 --- a/libs/libxx/uClibc++/system_configuration.h +++ b/libs/libxx/uClibc++/system_configuration.h @@ -1,8 +1,8 @@ /**************************************************************************** - * libs/libxx/system_configuration.h + * libs/libxx/uClibc++/system_configuration.h + * + * SPDX-License-Identifier: Apache-2.0 * -# SPDX-License-Identifier: Apache-2.0 -# * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The From eadfb5a2f8a87a459c3d011aac3a39befb9ff91d Mon Sep 17 00:00:00 2001 From: "lijing.ly" Date: Wed, 19 Feb 2025 13:14:37 +0800 Subject: [PATCH 21/33] boards/Kconfig: Add ARCH_CHIP_ESP32S3WROOM1N16R8 configuration item for Espressif ESP32-S3 DevKit Signed-off-by: lijing.ly --- boards/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/Kconfig b/boards/Kconfig index 918c7b1ef1e47..0a44beed6961a 100644 --- a/boards/Kconfig +++ b/boards/Kconfig @@ -423,7 +423,7 @@ config ARCH_BOARD_FRANZININHO_WIFI config ARCH_BOARD_ESP32S3_DEVKIT bool "Espressif ESP32-S3 DevKit" - depends on ARCH_CHIP_ESP32S3WROOM1N4 || ARCH_CHIP_ESP32S3MINI1N8 || ARCH_CHIP_ESP32S3WROOM2N16R8V || ARCH_CHIP_ESP32S3WROOM2N32R8V || ARCH_CHIP_ESP32S3CUSTOM || ARCH_CHIP_ESP32S3WROOM1N8R8 + depends on ARCH_CHIP_ESP32S3WROOM1N4 || ARCH_CHIP_ESP32S3MINI1N8 || ARCH_CHIP_ESP32S3WROOM1N16R8 || ARCH_CHIP_ESP32S3WROOM2N16R8V || ARCH_CHIP_ESP32S3WROOM2N32R8V || ARCH_CHIP_ESP32S3CUSTOM || ARCH_CHIP_ESP32S3WROOM1N8R8 select ARCH_HAVE_LEDS select ARCH_HAVE_BUTTONS select ARCH_HAVE_IRQBUTTONS if ESP32S3_GPIO_IRQ From fd6d80462303fc363d885150e49f9c5f175639c5 Mon Sep 17 00:00:00 2001 From: Luchian Mihai Date: Sat, 15 Feb 2025 12:27:13 +0200 Subject: [PATCH 22/33] tools/nxstyle: handle case statement fix nxstyle so it throw error if case statement is not on new line --- tools/nxstyle.c | 61 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/tools/nxstyle.c b/tools/nxstyle.c index 1937976398fd5..8179921c44393 100644 --- a/tools/nxstyle.c +++ b/tools/nxstyle.c @@ -1133,6 +1133,7 @@ int main(int argc, char **argv, char **envp) bool bfor; /* True: This line is beginning of a 'for' statement */ bool bif; /* True: This line is beginning of a 'if' statement */ bool bswitch; /* True: Within a switch statement */ + bool bcase; /* True: Within a case statement of a switch */ bool bstring; /* True: Within a string */ bool bquote; /* True: Backslash quoted character next */ bool bblank; /* Used to verify block comment terminator */ @@ -1269,6 +1270,7 @@ int main(int argc, char **argv, char **envp) bcrs = false; /* True: Carriage return found on the line */ bfunctions = false; /* True: In private or public functions */ bswitch = false; /* True: Within a switch statement */ + bcase = false; /* True: Within a case statement of a switch */ bstring = false; /* True: Within a string */ bexternc = false; /* True: Within 'extern "C"' */ bif = false; /* True: This line is beginning of a 'if' statement */ @@ -2004,22 +2006,11 @@ int main(int argc, char **argv, char **envp) */ else if (strncmp(&line[indent], "break ", 6) == 0 || - strncmp(&line[indent], "case ", 5) == 0 || - #if 0 /* Part of switch */ - strncmp(&line[indent], "case ", 5) == 0 || - #endif strncmp(&line[indent], "continue ", 9) == 0 || - - #if 0 /* Part of switch */ - strncmp(&line[indent], "default ", 8) == 0 || - #endif strncmp(&line[indent], "do ", 3) == 0 || strncmp(&line[indent], "else ", 5) == 0 || strncmp(&line[indent], "goto ", 5) == 0 || strncmp(&line[indent], "return ", 7) == 0 || - #if 0 /* Doesn't follow pattern */ - strncmp(&line[indent], "switch ", 7) == 0 || - #endif strncmp(&line[indent], "while ", 6) == 0) { bstatm = true; @@ -2042,6 +2033,29 @@ int main(int argc, char **argv, char **envp) { bswitch = true; } + else if (strncmp(&line[indent], "switch(", 7) == 0) + { + ERROR("Missing whitespace after keyword", lineno, n); + bswitch = true; + } + else if (strncmp(&line[indent], "case ", 5) == 0) + { + bcase = true; + } + else if (strncmp(&line[indent], "case(", 5) == 0) + { + ERROR("Missing whitespace after keyword", lineno, n); + bcase = true; + } + else if (strncmp(&line[indent], "default ", 8) == 0) + { + ERROR("Missing whitespace after keyword", lineno, n); + bcase = true; + } + else if (strncmp(&line[indent], "default:", 8) == 0) + { + bcase = true; + } /* Also check for C keywords with missing white space */ @@ -2063,11 +2077,6 @@ int main(int argc, char **argv, char **envp) bfor = true; bstatm = true; } - else if (strncmp(&line[indent], "switch(", 7) == 0) - { - ERROR("Missing whitespace after keyword", lineno, n); - bswitch = true; - } } /* STEP 3: Parse each character on the line */ @@ -2731,9 +2740,26 @@ int main(int argc, char **argv, char **envp) } } break; + case ':': + { + if (bcase == true) + { + char *ndx = &line[n + 1]; + while ((int)isspace(*ndx)) + { + ndx++; + } - /* Semi-colon may terminate a declaration */ + if (*ndx != '\0' && *ndx != '/') + { + ERROR("Case statement should be on a new line", + lineno, n); + } + bcase = false; + } + } + break; case ',': { if (!isspace((int)line[n + 1])) @@ -3072,7 +3098,6 @@ int main(int argc, char **argv, char **envp) } break; - case '^': /* ^= */ From 9f85eaf3cb51ca79b0fca4ba9821afe997b5e615 Mon Sep 17 00:00:00 2001 From: wangjianyu3 Date: Sat, 22 Feb 2025 07:58:05 +0800 Subject: [PATCH 23/33] drivers/thermal: Fix work not queued after getting temperature fails The work will be stopped after get_temp() fails. Signed-off-by: wangjianyu3 --- drivers/thermal/thermal_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 74d3e349a28ef..f0c9196292931 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -835,7 +835,7 @@ void thermal_zone_device_update(FAR struct thermal_zone_device_s *zdev) if (ret < 0) { therr("Failed to get temperature from zone %s \n", zdev->name); - goto unlock; + goto delayed_work; } zdev->last_temperature = zdev->temperature; @@ -896,6 +896,8 @@ void thermal_zone_device_update(FAR struct thermal_zone_device_s *zdev) } } +delayed_work: + /* Update worker invoke delay */ delay = zdev->params->passive_delay; From 34aa17b7a06fb53ab4fc68b523450aa9f3517ab9 Mon Sep 17 00:00:00 2001 From: Laczen JMS Date: Thu, 20 Feb 2025 09:27:59 +0100 Subject: [PATCH 24/33] sixlowpan: improve tcp support. Update the handling of tcp packets over sixlowpan. `tcp_ipv6_input()` can update the dev->d_iob. Assigning ipv6 to IPv6BUF makes sure that the correct buffer is used. Signed-off-by: Laczen JMS --- net/devif/ipv6_input.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/devif/ipv6_input.c b/net/devif/ipv6_input.c index 6216c9d1e013c..af9d9cdbeed1a 100644 --- a/net/devif/ipv6_input.c +++ b/net/devif/ipv6_input.c @@ -463,6 +463,12 @@ static int ipv6_in(FAR struct net_driver_s *dev) if ((dev->d_len > 0 && dev->d_lltype == NET_LL_IEEE802154) || (dev->d_len > 0 && dev->d_lltype == NET_LL_PKTRADIO)) { + /* tcp_ipv6_input() can update dev->d_iob. Update ipv6 to ensure + * using the correct data. + */ + + ipv6 = IPv6BUF; + /* Let 6LoWPAN handle the TCP output */ sixlowpan_tcp_send(dev, dev, ipv6); From 17a80e90bd998cfaa561c9f5f618616c5b7e23c2 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Thu, 30 Jan 2025 15:11:39 +0200 Subject: [PATCH 25/33] arch/mcx-nxxx: Add support for NXP MCX-N236 CPU This adds minimal support for NXP MCX-N236 CPU. Peripherals supported are: - GPIO - PINMUX - CLOCK - LPUART An example board, FRDM-MCXN236 is also added, with a basic profile that boots into nsh. Signed-off-by: Ville Juven --- arch/arm/Kconfig | 12 + arch/arm/include/mcx-nxxx/chip.h | 60 + arch/arm/include/mcx-nxxx/irq.h | 72 + arch/arm/include/mcx-nxxx/n236_irq.h | 189 ++ arch/arm/src/mcx-nxxx/CMakeLists.txt | 40 + arch/arm/src/mcx-nxxx/Kconfig | 118 + arch/arm/src/mcx-nxxx/Make.defs | 36 + arch/arm/src/mcx-nxxx/chip.h | 48 + .../src/mcx-nxxx/hardware/n236/n236_clock.h | 728 +++++ .../src/mcx-nxxx/hardware/n236/n236_gpio.h | 61 + .../mcx-nxxx/hardware/n236/n236_memorymap.h | 159 + arch/arm/src/mcx-nxxx/hardware/nxxx_clock.h | 78 + .../arm/src/mcx-nxxx/hardware/nxxx_flexcomm.h | 95 + arch/arm/src/mcx-nxxx/hardware/nxxx_fmu.h | 144 + arch/arm/src/mcx-nxxx/hardware/nxxx_gpio.h | 108 + arch/arm/src/mcx-nxxx/hardware/nxxx_lpuart.h | 315 ++ .../src/mcx-nxxx/hardware/nxxx_memorymap.h | 38 + arch/arm/src/mcx-nxxx/hardware/nxxx_port.h | 112 + arch/arm/src/mcx-nxxx/hardware/nxxx_scg.h | 535 ++++ arch/arm/src/mcx-nxxx/hardware/nxxx_spc.h | 495 +++ arch/arm/src/mcx-nxxx/nxxx_clockconfig.c | 438 +++ arch/arm/src/mcx-nxxx/nxxx_clockconfig.h | 118 + arch/arm/src/mcx-nxxx/nxxx_gpio.c | 279 ++ arch/arm/src/mcx-nxxx/nxxx_gpio.h | 340 +++ arch/arm/src/mcx-nxxx/nxxx_gpiobase.c | 53 + arch/arm/src/mcx-nxxx/nxxx_gpioirq.c | 316 ++ arch/arm/src/mcx-nxxx/nxxx_idle.c | 82 + arch/arm/src/mcx-nxxx/nxxx_irq.c | 669 +++++ arch/arm/src/mcx-nxxx/nxxx_lowputc.c | 599 ++++ arch/arm/src/mcx-nxxx/nxxx_lowputc.h | 95 + arch/arm/src/mcx-nxxx/nxxx_lpuart.c | 2656 +++++++++++++++++ arch/arm/src/mcx-nxxx/nxxx_port.c | 83 + arch/arm/src/mcx-nxxx/nxxx_port.h | 98 + arch/arm/src/mcx-nxxx/nxxx_serial.h | 251 ++ arch/arm/src/mcx-nxxx/nxxx_start.c | 185 ++ arch/arm/src/mcx-nxxx/nxxx_timerisr.c | 106 + boards/Kconfig | 12 + .../arm/mcx-nxxx/frdm-mcxn236/CMakeLists.txt | 23 + boards/arm/mcx-nxxx/frdm-mcxn236/Kconfig | 4 + .../frdm-mcxn236/configs/nsh/defconfig | 48 + .../arm/mcx-nxxx/frdm-mcxn236/include/board.h | 83 + .../mcx-nxxx/frdm-mcxn236/scripts/Make.defs | 36 + .../mcx-nxxx/frdm-mcxn236/scripts/flash.ld | 117 + .../frdm-mcxn236/scripts/mcx_n236.jlink | 47 + .../mcx-nxxx/frdm-mcxn236/src/CMakeLists.txt | 31 + boards/arm/mcx-nxxx/frdm-mcxn236/src/Makefile | 31 + .../mcx-nxxx/frdm-mcxn236/src/frdm-mcxn236.h | 61 + .../mcx-nxxx/frdm-mcxn236/src/n23x_appinit.c | 76 + .../frdm-mcxn236/src/n23x_boardinit.c | 90 + .../mcx-nxxx/frdm-mcxn236/src/n23x_bringup.c | 62 + 50 files changed, 10532 insertions(+) create mode 100644 arch/arm/include/mcx-nxxx/chip.h create mode 100644 arch/arm/include/mcx-nxxx/irq.h create mode 100644 arch/arm/include/mcx-nxxx/n236_irq.h create mode 100644 arch/arm/src/mcx-nxxx/CMakeLists.txt create mode 100644 arch/arm/src/mcx-nxxx/Kconfig create mode 100644 arch/arm/src/mcx-nxxx/Make.defs create mode 100644 arch/arm/src/mcx-nxxx/chip.h create mode 100644 arch/arm/src/mcx-nxxx/hardware/n236/n236_clock.h create mode 100644 arch/arm/src/mcx-nxxx/hardware/n236/n236_gpio.h create mode 100644 arch/arm/src/mcx-nxxx/hardware/n236/n236_memorymap.h create mode 100644 arch/arm/src/mcx-nxxx/hardware/nxxx_clock.h create mode 100644 arch/arm/src/mcx-nxxx/hardware/nxxx_flexcomm.h create mode 100644 arch/arm/src/mcx-nxxx/hardware/nxxx_fmu.h create mode 100644 arch/arm/src/mcx-nxxx/hardware/nxxx_gpio.h create mode 100644 arch/arm/src/mcx-nxxx/hardware/nxxx_lpuart.h create mode 100644 arch/arm/src/mcx-nxxx/hardware/nxxx_memorymap.h create mode 100644 arch/arm/src/mcx-nxxx/hardware/nxxx_port.h create mode 100644 arch/arm/src/mcx-nxxx/hardware/nxxx_scg.h create mode 100644 arch/arm/src/mcx-nxxx/hardware/nxxx_spc.h create mode 100644 arch/arm/src/mcx-nxxx/nxxx_clockconfig.c create mode 100644 arch/arm/src/mcx-nxxx/nxxx_clockconfig.h create mode 100644 arch/arm/src/mcx-nxxx/nxxx_gpio.c create mode 100644 arch/arm/src/mcx-nxxx/nxxx_gpio.h create mode 100644 arch/arm/src/mcx-nxxx/nxxx_gpiobase.c create mode 100644 arch/arm/src/mcx-nxxx/nxxx_gpioirq.c create mode 100644 arch/arm/src/mcx-nxxx/nxxx_idle.c create mode 100644 arch/arm/src/mcx-nxxx/nxxx_irq.c create mode 100644 arch/arm/src/mcx-nxxx/nxxx_lowputc.c create mode 100644 arch/arm/src/mcx-nxxx/nxxx_lowputc.h create mode 100644 arch/arm/src/mcx-nxxx/nxxx_lpuart.c create mode 100644 arch/arm/src/mcx-nxxx/nxxx_port.c create mode 100644 arch/arm/src/mcx-nxxx/nxxx_port.h create mode 100644 arch/arm/src/mcx-nxxx/nxxx_serial.h create mode 100644 arch/arm/src/mcx-nxxx/nxxx_start.c create mode 100644 arch/arm/src/mcx-nxxx/nxxx_timerisr.c create mode 100644 boards/arm/mcx-nxxx/frdm-mcxn236/CMakeLists.txt create mode 100644 boards/arm/mcx-nxxx/frdm-mcxn236/Kconfig create mode 100644 boards/arm/mcx-nxxx/frdm-mcxn236/configs/nsh/defconfig create mode 100644 boards/arm/mcx-nxxx/frdm-mcxn236/include/board.h create mode 100644 boards/arm/mcx-nxxx/frdm-mcxn236/scripts/Make.defs create mode 100644 boards/arm/mcx-nxxx/frdm-mcxn236/scripts/flash.ld create mode 100644 boards/arm/mcx-nxxx/frdm-mcxn236/scripts/mcx_n236.jlink create mode 100644 boards/arm/mcx-nxxx/frdm-mcxn236/src/CMakeLists.txt create mode 100644 boards/arm/mcx-nxxx/frdm-mcxn236/src/Makefile create mode 100644 boards/arm/mcx-nxxx/frdm-mcxn236/src/frdm-mcxn236.h create mode 100644 boards/arm/mcx-nxxx/frdm-mcxn236/src/n23x_appinit.c create mode 100644 boards/arm/mcx-nxxx/frdm-mcxn236/src/n23x_boardinit.c create mode 100644 boards/arm/mcx-nxxx/frdm-mcxn236/src/n23x_bringup.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 04c0c3af7b42a..560a6e42229cb 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -354,6 +354,14 @@ config ARCH_CHIP_NUC1XX ---help--- Nuvoton NUC100/120 architectures (ARM Cortex-M0). +config ARCH_CHIP_MCX_NXXX + bool "NXP MCX NXXx Cortex-M33" + select ARCH_CORTEXM33 + select ARCH_HAVE_FPU + select ARCH_HAVE_DFPU + ---help--- + NXXx architectures (Cortex-M33) + config ARCH_CHIP_RP2040 bool "Raspberry Pi RP2040" select ARCH_CORTEXM0 @@ -1187,6 +1195,7 @@ config ARCH_CHIP default "at32" if ARCH_CHIP_AT32 default "cxd32xx" if ARCH_CHIP_CXD32XX default "csk6" if ARCH_CHIP_CSK6 + default "mcx-nxxx" if ARCH_CHIP_MCX_NXXX config ARM_THUMB bool "Thumb Mode" @@ -1703,4 +1712,7 @@ endif if ARCH_CHIP_CXD32XX source "arch/arm/src/cxd32xx/Kconfig" endif +if ARCH_CHIP_MCX_NXXX +source "arch/arm/src/mcx-nxxx/Kconfig" +endif endif # ARCH_ARM diff --git a/arch/arm/include/mcx-nxxx/chip.h b/arch/arm/include/mcx-nxxx/chip.h new file mode 100644 index 0000000000000..775cc0be3799a --- /dev/null +++ b/arch/arm/include/mcx-nxxx/chip.h @@ -0,0 +1,60 @@ +/**************************************************************************** + * arch/arm/include/mcx-nxxx/chip.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_INCLUDE_MCX_NXXX_CHIP_H +#define __ARCH_ARM_INCLUDE_MCX_NXXX_CHIP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Cache line sizes (in bytes) for the MCX_NXXX (Cortex-M33). MCX_NXXX has + * two caches; LPCACHE which is the instruction cache, and CACHE64 which is + * for FlexSPI (Not present on n23x-series). + * + * There is no generic data cache. + */ + +#define ARMV8M_ICACHE_LINESIZE 16 /* 16 bytes (4 words, Cortex-M33 only) */ +#define ARMV8M_DCACHE_LINESIZE 32 /* 32 bytes (8 words, FlexSPI only) */ + +/* NVIC priority levels *****************************************************/ + +/* Each priority field holds an 8-bit priority value, 0-15. The lower the + * value, the greater the priority of the corresponding interrupt. nx94x uses + * msbits [7:5] for priority and the rest are reserved. + */ + +#define NVIC_SYSH_PRIORITY_MIN 0xe0 /* E0h is minimum priority */ +#define NVIC_SYSH_PRIORITY_DEFAULT 0x80 /* Midpoint is the default */ +#define NVIC_SYSH_PRIORITY_MAX 0x00 /* Zero is maximum priority */ +#define NVIC_SYSH_PRIORITY_STEP 0x20 /* Step is the 5th bit */ + +#define NXXX_GPIO_NPORTS 6 + +#endif /* __ARCH_ARM_INCLUDE_MCX_NXXX_CHIP_H */ diff --git a/arch/arm/include/mcx-nxxx/irq.h b/arch/arm/include/mcx-nxxx/irq.h new file mode 100644 index 0000000000000..3c549ceab9d54 --- /dev/null +++ b/arch/arm/include/mcx-nxxx/irq.h @@ -0,0 +1,72 @@ +/**************************************************************************** + * arch/arm/include/mcx-nxxx/irq.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* This file should never be included directly but, rather, + * only indirectly through nuttx/irq.h + */ + +#ifndef __ARCH_ARM_INCLUDE_MCX_NXXX_IRQ_H +#define __ARCH_ARM_INCLUDE_MCX_NXXX_IRQ_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#if defined(CONFIG_ARCH_CHIP_N236) +# include +#else +# error "Unrecognized MCX-NXXx architecture" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* IRQ numbers. The IRQ number corresponds vector number and hence map + * directly to bits in the NVIC. This does, however, waste several words + * of memory in the IRQ to handle mapping tables. + */ + +/* Common Processor Exceptions (vectors 0-15) */ + +#define NXXX_IRQ_RESERVED (0) /* Vector 0: Reset stack pointer value */ + /* Vector 1: Reset(not handled by IRQ) */ +#define NXXX_IRQ_NMI (2) /* Vector 2: Non-Maskable Int (NMI) */ +#define NXXX_IRQ_HARDFAULT (3) /* Vector 3: Hard fault */ +#define NXXX_IRQ_MEMFAULT (4) /* Vector 4: MemManage fault */ +#define NXXX_IRQ_BUSFAULT (5) /* Vector 5: Bus fault */ +#define NXXX_IRQ_USAGEFAULT (6) /* Vector 6: Usage fault */ +#define NXXX_IRQ_USAGEFAULT (6) /* Vector 7: Secure fault */ + /* Vectors 8-10: Reserved */ +#define NXXX_IRQ_SVCALL (11) /* Vector 11: Supervisor Call (SVC) */ +#define NXXX_IRQ_DBGMONITOR (12) /* Vector 12: Debug Monitor */ + /* Vector 13: Reserved */ +#define NXXX_IRQ_PENDSV (14) /* Vector 14: Pendable System Service Request */ +#define NXXX_IRQ_SYSTICK (15) /* Vector 15: System tick */ + +/* Chip-Specific External interrupts */ + +#define NXXX_IRQ_EXTINT (16) /* Vector number of the first external interrupt*/ + +#endif /* __ARCH_ARM_INCLUDE_MCX_NXXX_IRQ_H */ diff --git a/arch/arm/include/mcx-nxxx/n236_irq.h b/arch/arm/include/mcx-nxxx/n236_irq.h new file mode 100644 index 0000000000000..6a3026415cd2b --- /dev/null +++ b/arch/arm/include/mcx-nxxx/n236_irq.h @@ -0,0 +1,189 @@ +/**************************************************************************** + * arch/arm/include/mcx-nxxx/n236_irq.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef ARCH_ARM_INCLUDE_MCX_NXXX_N236_IRQ_H +#define ARCH_ARM_INCLUDE_MCX_NXXX_N236_IRQ_H + +#define NXXX_IRQ_OR (NXXX_IRQ_EXTINT + 0) /**< OR IRQ */ +#define NXXX_IRQ_EDMA_0_CH0 (NXXX_IRQ_EXTINT + 1) /**< eDMA_0_CH0 error or transfer complete */ +#define NXXX_IRQ_EDMA_0_CH1 (NXXX_IRQ_EXTINT + 2) /**< eDMA_0_CH1 error or transfer complete */ +#define NXXX_IRQ_EDMA_0_CH2 (NXXX_IRQ_EXTINT + 3) /**< eDMA_0_CH2 error or transfer complete */ +#define NXXX_IRQ_EDMA_0_CH3 (NXXX_IRQ_EXTINT + 4) /**< eDMA_0_CH3 error or transfer complete */ +#define NXXX_IRQ_EDMA_0_CH4 (NXXX_IRQ_EXTINT + 5) /**< eDMA_0_CH4 error or transfer complete */ +#define NXXX_IRQ_EDMA_0_CH5 (NXXX_IRQ_EXTINT + 6) /**< eDMA_0_CH5 error or transfer complete */ +#define NXXX_IRQ_EDMA_0_CH6 (NXXX_IRQ_EXTINT + 7) /**< eDMA_0_CH6 error or transfer complete */ +#define NXXX_IRQ_EDMA_0_CH7 (NXXX_IRQ_EXTINT + 8) /**< eDMA_0_CH7 error or transfer complete */ +#define NXXX_IRQ_EDMA_0_CH8 (NXXX_IRQ_EXTINT + 9) /**< eDMA_0_CH8 error or transfer complete */ +#define NXXX_IRQ_EDMA_0_CH9 (NXXX_IRQ_EXTINT + 10) /**< eDMA_0_CH9 error or transfer complete */ +#define NXXX_IRQ_EDMA_0_CH10 (NXXX_IRQ_EXTINT + 11) /**< eDMA_0_CH10 error or transfer complete */ +#define NXXX_IRQ_EDMA_0_CH11 (NXXX_IRQ_EXTINT + 12) /**< eDMA_0_CH11 error or transfer complete */ +#define NXXX_IRQ_EDMA_0_CH12 (NXXX_IRQ_EXTINT + 13) /**< eDMA_0_CH12 error or transfer complete */ +#define NXXX_IRQ_EDMA_0_CH13 (NXXX_IRQ_EXTINT + 14) /**< eDMA_0_CH13 error or transfer complete */ +#define NXXX_IRQ_EDMA_0_CH14 (NXXX_IRQ_EXTINT + 15) /**< eDMA_0_CH14 error or transfer complete */ +#define NXXX_IRQ_EDMA_0_CH15 (NXXX_IRQ_EXTINT + 16) /**< eDMA_0_CH15 error or transfer complete */ +#define NXXX_IRQ_GPIO00 (NXXX_IRQ_EXTINT + 17) /**< GPIO0 interrupt 0 */ +#define NXXX_IRQ_GPIO01 (NXXX_IRQ_EXTINT + 18) /**< GPIO0 interrupt 1 */ +#define NXXX_IRQ_GPIO10 (NXXX_IRQ_EXTINT + 19) /**< GPIO1 interrupt 0 */ +#define NXXX_IRQ_GPIO11 (NXXX_IRQ_EXTINT + 20) /**< GPIO1 interrupt 1 */ +#define NXXX_IRQ_GPIO20 (NXXX_IRQ_EXTINT + 21) /**< GPIO2 interrupt 0 */ +#define NXXX_IRQ_GPIO21 (NXXX_IRQ_EXTINT + 22) /**< GPIO2 interrupt 1 */ +#define NXXX_IRQ_GPIO30 (NXXX_IRQ_EXTINT + 23) /**< GPIO3 interrupt 0 */ +#define NXXX_IRQ_GPIO31 (NXXX_IRQ_EXTINT + 24) /**< GPIO3 interrupt 1 */ +#define NXXX_IRQ_GPIO40 (NXXX_IRQ_EXTINT + 25) /**< GPIO4 interrupt 0 */ +#define NXXX_IRQ_GPIO41 (NXXX_IRQ_EXTINT + 26) /**< GPIO4 interrupt 1 */ +#define NXXX_IRQ_GPIO50 (NXXX_IRQ_EXTINT + 27) /**< GPIO5 interrupt 0 */ +#define NXXX_IRQ_GPIO51 (NXXX_IRQ_EXTINT + 28) /**< GPIO5 interrupt 1 */ +#define NXXX_IRQ_UTICK0 (NXXX_IRQ_EXTINT + 29) /**< Micro-Tick Timer interrupt */ +#define NXXX_IRQ_MRT0 (NXXX_IRQ_EXTINT + 30) /**< Multi-Rate Timer interrupt */ +#define NXXX_IRQ_CTIMER0 (NXXX_IRQ_EXTINT + 31) /**< Standard counter/timer 0 interrupt */ +#define NXXX_IRQ_CTIMER1 (NXXX_IRQ_EXTINT + 32) /**< Standard counter/timer 1 interrupt */ +#define NXXX_IRQ_RESERVED49 (NXXX_IRQ_EXTINT + 33) /**< Reserved interrupt */ +#define NXXX_IRQ_CTIMER2 (NXXX_IRQ_EXTINT + 34) /**< Standard counter/timer 2 interrupt */ +#define NXXX_IRQ_LP_FLEXCOMM0 (NXXX_IRQ_EXTINT + 35) /**< LP_FLEXCOMM0 (NXXX_IRQ_EXTINT + LPSPI interrupt or LPI2C interrupt or LPUART Receive/Transmit interrupt) */ +#define NXXX_IRQ_LP_FLEXCOMM1 (NXXX_IRQ_EXTINT + 36) /**< LP_FLEXCOMM1 (NXXX_IRQ_EXTINT + LPSPI interrupt or LPI2C interrupt or LPUART Receive/Transmit interrupt) */ +#define NXXX_IRQ_LP_FLEXCOMM2 (NXXX_IRQ_EXTINT + 37) /**< LP_FLEXCOMM2 (NXXX_IRQ_EXTINT + LPSPI interrupt or LPI2C interrupt or LPUART Receive/Transmit interrupt) */ +#define NXXX_IRQ_LP_FLEXCOMM3 (NXXX_IRQ_EXTINT + 38) /**< LP_FLEXCOMM3 (NXXX_IRQ_EXTINT + LPSPI interrupt or LPI2C interrupt or LPUART Receive/Transmit interrupt) */ +#define NXXX_IRQ_LP_FLEXCOMM4 (NXXX_IRQ_EXTINT + 39) /**< LP_FLEXCOMM4 (NXXX_IRQ_EXTINT + LPSPI interrupt or LPI2C interrupt or LPUART Receive/Transmit interrupt) */ +#define NXXX_IRQ_LP_FLEXCOMM5 (NXXX_IRQ_EXTINT + 40) /**< LP_FLEXCOMM5 (NXXX_IRQ_EXTINT + LPSPI interrupt or LPI2C interrupt or LPUART Receive/Transmit interrupt) */ +#define NXXX_IRQ_LP_FLEXCOMM6 (NXXX_IRQ_EXTINT + 41) /**< LP_FLEXCOMM6 (NXXX_IRQ_EXTINT + LPSPI interrupt or LPI2C interrupt or LPUART Receive/Transmit interrupt) */ +#define NXXX_IRQ_LP_FLEXCOMM7 (NXXX_IRQ_EXTINT + 42) /**< LP_FLEXCOMM7 (NXXX_IRQ_EXTINT + LPSPI interrupt or LPI2C interrupt or LPUART Receive/Transmit interrupt) */ +#define NXXX_IRQ_RESERVED59 (NXXX_IRQ_EXTINT + 43) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED60 (NXXX_IRQ_EXTINT + 44) /**< Reserved interrupt */ +#define NXXX_IRQ_ADC0 (NXXX_IRQ_EXTINT + 45) /**< Analog-to-Digital Converter 0 - General Purpose interrupt */ +#define NXXX_IRQ_ADC1 (NXXX_IRQ_EXTINT + 46) /**< Analog-to-Digital Converter 1 - General Purpose interrupt */ +#define NXXX_IRQ_PINT0 (NXXX_IRQ_EXTINT + 47) /**< Pin Interrupt Pattern Match Interrupt */ +#define NXXX_IRQ_PDM_EVENT (NXXX_IRQ_EXTINT + 48) /**< Microphone Interface interrupt */ +#define NXXX_IRQ_RESERVED65 (NXXX_IRQ_EXTINT + 49) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED66 (NXXX_IRQ_EXTINT + 50) /**< Reserved interrupt */ +#define NXXX_IRQ_USB0_DCD (NXXX_IRQ_EXTINT + 51) /**< Universal Serial Bus - Device Charge Detect interrupt */ +#define NXXX_IRQ_RTC (NXXX_IRQ_EXTINT + 52) /**< RTC Subsystem interrupt (NXXX_IRQ_EXTINT + RTC interrupt or Wake timer interrupt) */ +#define NXXX_IRQ_SMARTDMA (NXXX_IRQ_EXTINT + 53) /**< SmartDMA_IRQ */ +#define NXXX_IRQ_RESERVED70 (NXXX_IRQ_EXTINT + 54) /**< Reserved interrupt */ +#define NXXX_IRQ_CTIMER3 (NXXX_IRQ_EXTINT + 55) /**< Standard counter/timer 3 interrupt */ +#define NXXX_IRQ_CTIMER4 (NXXX_IRQ_EXTINT + 56) /**< Standard counter/timer 4 interrupt */ +#define NXXX_IRQ_OS_EVENT (NXXX_IRQ_EXTINT + 57) /**< OS event timer interrupt */ +#define NXXX_IRQ_RESERVED74 (NXXX_IRQ_EXTINT + 58) /**< Reserved interrupt */ +#define NXXX_IRQ_SAI0 (NXXX_IRQ_EXTINT + 59) /**< Serial Audio Interface 0 interrupt */ +#define NXXX_IRQ_SAI1 (NXXX_IRQ_EXTINT + 60) /**< Serial Audio Interface 1 interrupt */ +#define NXXX_IRQ_RESERVED77 (NXXX_IRQ_EXTINT + 61) /**< Reserved interrupt */ +#define NXXX_IRQ_CAN0 (NXXX_IRQ_EXTINT + 62) /**< Controller Area Network 0 interrupt */ +#define NXXX_IRQ_CAN1 (NXXX_IRQ_EXTINT + 63) /**< Controller Area Network 1 interrupt */ +#define NXXX_IRQ_RESERVED80 (NXXX_IRQ_EXTINT + 64) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED81 (NXXX_IRQ_EXTINT + 65) /**< Reserved interrupt */ +#define NXXX_IRQ_USB1_HS_PHY (NXXX_IRQ_EXTINT + 66) /**< USBHS DCD or USBHS Phy interrupt */ +#define NXXX_IRQ_USB1_HS (NXXX_IRQ_EXTINT + 67) /**< USB High Speed OTG Controller interrupt */ +#define NXXX_IRQ_SEC_HYPERVISOR_CALL (NXXX_IRQ_EXTINT + 68) /**< AHB Secure Controller hypervisor call interrupt */ +#define NXXX_IRQ_RESERVED85 (NXXX_IRQ_EXTINT + 69) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED86 (NXXX_IRQ_EXTINT + 70) /**< Reserved interrupt */ +#define NXXX_IRQ_FREQME (NXXX_IRQ_EXTINT + 71) /**< Frequency Measurement interrupt */ +#define NXXX_IRQ_SEC_VIO (NXXX_IRQ_EXTINT + 72) /**< Secure violation interrupt (NXXX_IRQ_EXTINT + Memory Block Checker interrupt or secure AHB matrix violation interrupt) */ +#define NXXX_IRQ_ELS (NXXX_IRQ_EXTINT + 73) /**< ELS interrupt */ +#define NXXX_IRQ_PKC (NXXX_IRQ_EXTINT + 74) /**< PKC interrupt */ +#define NXXX_IRQ_PUF (NXXX_IRQ_EXTINT + 75) /**< Physical Unclonable Function interrupt */ +#define NXXX_IRQ_RESERVED92 (NXXX_IRQ_EXTINT + 76) /**< Reserved interrupt */ +#define NXXX_IRQ_EDMA_1_CH0 (NXXX_IRQ_EXTINT + 77) /**< eDMA_1_CH0 error or transfer complete */ +#define NXXX_IRQ_EDMA_1_CH1 (NXXX_IRQ_EXTINT + 78) /**< eDMA_1_CH1 error or transfer complete */ +#define NXXX_IRQ_EDMA_1_CH2 (NXXX_IRQ_EXTINT + 79) /**< eDMA_1_CH2 error or transfer complete */ +#define NXXX_IRQ_EDMA_1_CH3 (NXXX_IRQ_EXTINT + 80) /**< eDMA_1_CH3 error or transfer complete */ +#define NXXX_IRQ_EDMA_1_CH4 (NXXX_IRQ_EXTINT + 81) /**< eDMA_1_CH4 error or transfer complete */ +#define NXXX_IRQ_EDMA_1_CH5 (NXXX_IRQ_EXTINT + 82) /**< eDMA_1_CH5 error or transfer complete */ +#define NXXX_IRQ_EDMA_1_CH6 (NXXX_IRQ_EXTINT + 83) /**< eDMA_1_CH6 error or transfer complete */ +#define NXXX_IRQ_EDMA_1_CH7 (NXXX_IRQ_EXTINT + 84) /**< eDMA_1_CH7 error or transfer complete */ +#define NXXX_IRQ_RESERVED101 (NXXX_IRQ_EXTINT + 85) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED102 (NXXX_IRQ_EXTINT + 86) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED103 (NXXX_IRQ_EXTINT + 87) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED104 (NXXX_IRQ_EXTINT + 88) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED105 (NXXX_IRQ_EXTINT + 89) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED106 (NXXX_IRQ_EXTINT + 90) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED107 (NXXX_IRQ_EXTINT + 91) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED108 (NXXX_IRQ_EXTINT + 92) /**< Reserved interrupt */ +#define NXXX_IRQ_CDOG0 (NXXX_IRQ_EXTINT + 93) /**< Code Watchdog Timer 0 interrupt */ +#define NXXX_IRQ_CDOG1 (NXXX_IRQ_EXTINT + 94) /**< Code Watchdog Timer 1 interrupt */ +#define NXXX_IRQ_I3C0 (NXXX_IRQ_EXTINT + 95) /**< Improved Inter Integrated Circuit interrupt 0 */ +#define NXXX_IRQ_I3C1 (NXXX_IRQ_EXTINT + 96) /**< Improved Inter Integrated Circuit interrupt 1 */ +#define NXXX_IRQ_RESERVED113 (NXXX_IRQ_EXTINT + 97) /**< Reserved interrupt */ +#define NXXX_IRQ_GDET (NXXX_IRQ_EXTINT + 98) /**< Digital Glitch Detect 0 interrupt or Digital Glitch Detect 1 interrupt */ +#define NXXX_IRQ_VBAT0 (NXXX_IRQ_EXTINT + 99) /**< VBAT interrupt( VBAT interrupt or digital tamper interrupt) */ +#define NXXX_IRQ_EWM0 (NXXX_IRQ_EXTINT + 100) /**< External Watchdog Monitor interrupt */ +#define NXXX_IRQ_RESERVED117 (NXXX_IRQ_EXTINT + 101) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED118 (NXXX_IRQ_EXTINT + 102) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED119 (NXXX_IRQ_EXTINT + 103) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED120 (NXXX_IRQ_EXTINT + 104) /**< Reserved interrupt */ +#define NXXX_IRQ_FLEXIO (NXXX_IRQ_EXTINT + 105) /**< Flexible Input/Output interrupt */ +#define NXXX_IRQ_RESERVED122 (NXXX_IRQ_EXTINT + 106) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED123 (NXXX_IRQ_EXTINT + 107) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED124 (NXXX_IRQ_EXTINT + 108) /**< Reserved interrupt */ +#define NXXX_IRQ_HSCMP0 (NXXX_IRQ_EXTINT + 109) /**< High-Speed comparator0 interrupt */ +#define NXXX_IRQ_HSCMP1 (NXXX_IRQ_EXTINT + 110) /**< High-Speed comparator1 interrupt */ +#define NXXX_IRQ_RESERVED127 (NXXX_IRQ_EXTINT + 111) /**< Reserved interrupt */ +#define NXXX_IRQ_FLEXPWM0_RELOAD_ERROR (NXXX_IRQ_EXTINT + 112) /**< FlexPWM0_reload_error interrupt */ +#define NXXX_IRQ_FLEXPWM0_FAULT (NXXX_IRQ_EXTINT + 113) /**< FlexPWM0_fault interrupt */ +#define NXXX_IRQ_FLEXPWM0_SUBMODULE0 (NXXX_IRQ_EXTINT + 114) /**< FlexPWM0 Submodule 0 capture/compare/reload interrupt */ +#define NXXX_IRQ_FLEXPWM0_SUBMODULE1 (NXXX_IRQ_EXTINT + 115) /**< FlexPWM0 Submodule 1 capture/compare/reload interrupt */ +#define NXXX_IRQ_FLEXPWM0_SUBMODULE2 (NXXX_IRQ_EXTINT + 116) /**< FlexPWM0 Submodule 2 capture/compare/reload interrupt */ +#define NXXX_IRQ_FLEXPWM0_SUBMODULE3 (NXXX_IRQ_EXTINT + 117) /**< FlexPWM0 Submodule 3 capture/compare/reload interrupt */ +#define NXXX_IRQ_FLEXPWM1_RELOAD_ERROR (NXXX_IRQ_EXTINT + 118) /**< FlexPWM1_reload_error interrupt */ +#define NXXX_IRQ_FLEXPWM1_FAULT (NXXX_IRQ_EXTINT + 119) /**< FlexPWM1_fault interrupt */ +#define NXXX_IRQ_FLEXPWM1_SUBMODULE0 (NXXX_IRQ_EXTINT + 120) /**< FlexPWM1 Submodule 0 capture/compare/reload interrupt */ +#define NXXX_IRQ_FLEXPWM1_SUBMODULE1 (NXXX_IRQ_EXTINT + 121) /**< FlexPWM1 Submodule 1 capture/compare/reload interrupt */ +#define NXXX_IRQ_FLEXPWM1_SUBMODULE2 (NXXX_IRQ_EXTINT + 122) /**< FlexPWM1 Submodule 2 capture/compare/reload interrupt */ +#define NXXX_IRQ_FLEXPWM1_SUBMODULE3 (NXXX_IRQ_EXTINT + 123) /**< FlexPWM1 Submodule 3 capture/compare/reload interrupt */ +#define NXXX_IRQ_QDC0_COMPARE (NXXX_IRQ_EXTINT + 124) /**< QDC0_Compare interrupt */ +#define NXXX_IRQ_QDC0_HOME (NXXX_IRQ_EXTINT + 125) /**< QDC0_Home interrupt */ +#define NXXX_IRQ_QDC0_WDG_SAB (NXXX_IRQ_EXTINT + 126) /**< QDC0_WDG_IRQ/SAB interrupt */ +#define NXXX_IRQ_QDC0_IDX (NXXX_IRQ_EXTINT + 127) /**< QDC0_IDX interrupt */ +#define NXXX_IRQ_QDC1_COMPARE (NXXX_IRQ_EXTINT + 128) /**< QDC1_Compare interrupt */ +#define NXXX_IRQ_QDC1_HOME (NXXX_IRQ_EXTINT + 129) /**< QDC1_Home interrupt */ +#define NXXX_IRQ_QDC1_WDG_SAB (NXXX_IRQ_EXTINT + 130) /**< QDC1_WDG_IRQ/SAB interrupt */ +#define NXXX_IRQ_QDC1_IDX (NXXX_IRQ_EXTINT + 131) /**< QDC1_IDX interrupt */ +#define NXXX_IRQ_ITRC0 (NXXX_IRQ_EXTINT + 132) /**< Intrusion and Tamper Response Controller interrupt */ +#define NXXX_IRQ_RESERVED149 (NXXX_IRQ_EXTINT + 133) /**< Reserved interrupt */ +#define NXXX_IRQ_ELS_ERR (NXXX_IRQ_EXTINT + 134) /**< ELS error interrupt */ +#define NXXX_IRQ_PKC_ERR (NXXX_IRQ_EXTINT + 135) /**< PKC error interrupt */ +#define NXXX_IRQ_ERM_SINGLE_BIT_ERROR (NXXX_IRQ_EXTINT + 136) /**< ERM Single Bit error interrupt */ +#define NXXX_IRQ_ERM_MULTI_BIT_ERROR (NXXX_IRQ_EXTINT + 137) /**< ERM Multi Bit error interrupt */ +#define NXXX_IRQ_FMU0 (NXXX_IRQ_EXTINT + 138) /**< Flash Management Unit interrupt */ +#define NXXX_IRQ_RESERVED155 (NXXX_IRQ_EXTINT + 139) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED156 (NXXX_IRQ_EXTINT + 140) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED157 (NXXX_IRQ_EXTINT + 141) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED158 (NXXX_IRQ_EXTINT + 142) /**< Reserved interrupt */ +#define NXXX_IRQ_LPTMR0 (NXXX_IRQ_EXTINT + 143) /**< Low Power Timer 0 interrupt */ +#define NXXX_IRQ_LPTMR1 (NXXX_IRQ_EXTINT + 144) /**< Low Power Timer 1 interrupt */ +#define NXXX_IRQ_SCG (NXXX_IRQ_EXTINT + 145) /**< System Clock Generator interrupt */ +#define NXXX_IRQ_SPC (NXXX_IRQ_EXTINT + 146) /**< System Power Controller interrupt */ +#define NXXX_IRQ_WUU (NXXX_IRQ_EXTINT + 147) /**< Wake Up Unit interrupt */ +#define NXXX_IRQ_PORT_EFT (NXXX_IRQ_EXTINT + 148) /**< PORT0~5 EFT interrupt */ +#define NXXX_IRQ_RESERVED165 (NXXX_IRQ_EXTINT + 149) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED166 (NXXX_IRQ_EXTINT + 150) /**< Reserved interrupt */ +#define NXXX_IRQ_RESERVED167 (NXXX_IRQ_EXTINT + 151) /**< Reserved interrupt */ +#define NXXX_IRQ_WWDT0 (NXXX_IRQ_EXTINT + 152) /**< Windowed Watchdog Timer 0 interrupt */ +#define NXXX_IRQ_WWDT1 (NXXX_IRQ_EXTINT + 153) /**< Windowed Watchdog Timer 1 interrupt */ +#define NXXX_IRQ_CMC0 (NXXX_IRQ_EXTINT + 154) /**< Core Mode Controller interrupt */ +#define NXXX_IRQ_RESERVED171 (NXXX_IRQ_EXTINT + 155) /**< Reserved interrupt */ + +#define NXXX_IRQ_NEXTINT (156) + +/* Total amount of entries in system vector table */ + +#define NR_IRQS (NXXX_IRQ_EXTINT + NXXX_IRQ_NEXTINT) + +#endif /* ARCH_ARM_INCLUDE_MCX_NXXX_N236_IRQ_H */ diff --git a/arch/arm/src/mcx-nxxx/CMakeLists.txt b/arch/arm/src/mcx-nxxx/CMakeLists.txt new file mode 100644 index 0000000000000..06005b7df57b0 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/CMakeLists.txt @@ -0,0 +1,40 @@ +# ############################################################################## +# arch/arm/src/mcx-nxxx/CMakeLists.txt +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. The ASF licenses this +# file to you under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# ############################################################################## + +set(SRCS + nxxx_start.c + nxxx_clockconfig.c + nxxx_gpio.c + nxxx_port.c + nxxx_irq.c + nxxx_timerisr.c + nxxx_idle.c) + +if(CONFIG_NXXX_LPUART) + list(APPEND SRCS nxxx_lpuart.c nxxx_lowputc.c) +endif() + +if(CONFIG_NXXX_GPIO_IRQ) + list(APPEND SRCS nxxx_gpioirq.c) +endif() + +target_sources(arch PRIVATE ${SRCS}) diff --git a/arch/arm/src/mcx-nxxx/Kconfig b/arch/arm/src/mcx-nxxx/Kconfig new file mode 100644 index 0000000000000..e0c0434912149 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/Kconfig @@ -0,0 +1,118 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +if ARCH_CHIP_MCX_NXXX + +menu "MCX NXXx Chip Selection" + +choice + prompt "MCX NXXx Core Configuration" + default ARCH_CHIP_N236 + +config ARCH_CHIP_N236 + bool "MCXN236 Processor" + select ARCH_HAVE_RESET + select ARMV8M_HAVE_ICACHE + +endchoice # MCX NXXx Chip Selection + +endmenu # "MCX NXXx Chip Selection" + +menu "NXXX Peripheral Selection" + +menu "LPUART" + +config NXXX_LPUART + bool + default n + select ARCH_HAVE_SERIAL_TERMIOS + +config NXXX_LPUART1 + bool "LPUART1" + default n + select NXXX_LPUART + select LPUART1_SERIALDRIVER + +config NXXX_LPUART2 + bool "LPUART2" + default n + select NXXX_LPUART + select LPUART2_SERIALDRIVER + +config NXXX_LPUART3 + bool "LPUART3" + default n + select NXXX_LPUART + select LPUART3_SERIALDRIVER + +config NXXX_LPUART4 + bool "LPUART4" + default n + select NXXX_LPUART + select LPUART4_SERIALDRIVER + +config NXXX_LPUART5 + bool "LPUART5" + default n + select NXXX_LPUART + select LPUART5_SERIALDRIVER + +config NXXX_LPUART6 + bool "LPUART6" + default n + select NXXX_LPUART + select LPUART6_SERIALDRIVER + +config NXXX_LPUART7 + bool "LPUART7" + default n + select NXXX_LPUART + select LPUART7_SERIALDRIVER + +config NXXX_LPUART8 + bool "LPUART8" + default n + select NXXX_LPUART + select LPUART8_SERIALDRIVER + +config NXXX_LPUART9 + bool "LPUART9" + default n + select NXXX_LPUART + select LPUART9_SERIALDRIVER + +menu "LPUART Configuration" + depends on NXXX_LPUART + +config NXXX_LPUART_INVERT + bool "Signal Invert Support" + default n + +config NXXX_LPUART_SINGLEWIRE + bool "Signal Wire Support" + default n + +config NXXX_SERIAL_RXDMA_BUFFER_SIZE + int "RX DMA buffer size" + default 32 + depends on LPUART1_RXDMA || LPUART2_RXDMA || LPUART3_RXDMA || LPUART4_RXDMA || \ + LPUART5_RXDMA || LPUART6_RXDMA || LPUART7_RXDMA || LPUART8_RXDMA || \ + LPUART9_RXDMA + + ---help--- + The DMA buffer size when using RX DMA to emulate a FIFO. + + When streaming data, the generic serial layer will be called + every time the FIFO receives half this number of bytes. + + Value given here will be rounded up to next multiple of 32 bytes. + +endmenu # LPUART Configuration + +endmenu # LPUART + +endmenu # NXXX Peripheral Selection + +endif # ARCH_CHIP_NXXX diff --git a/arch/arm/src/mcx-nxxx/Make.defs b/arch/arm/src/mcx-nxxx/Make.defs new file mode 100644 index 0000000000000..76270e3c1087e --- /dev/null +++ b/arch/arm/src/mcx-nxxx/Make.defs @@ -0,0 +1,36 @@ +############################################################################ +# arch/arm/src/mcx-nxxx/Make.defs +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include armv8-m/Make.defs + +# NXXx-specific C source files + +CHIP_CSRCS = nxxx_start.c nxxx_clockconfig.c nxxx_gpio.c nxxx_port.c nxxx_irq.c +CHIP_CSRCS += nxxx_timerisr.c nxxx_idle.c + +ifeq ($(CONFIG_NXXX_LPUART),y) + CHIP_CSRCS += nxxx_lpuart.c nxxx_lowputc.c +endif + +ifeq ($(CONFIG_NXXX_GPIO_IRQ),y) + CHIP_CSRCS += nxxx_gpioirq.c +endif diff --git a/arch/arm/src/mcx-nxxx/chip.h b/arch/arm/src/mcx-nxxx/chip.h new file mode 100644 index 0000000000000..e5ab13fbb8424 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/chip.h @@ -0,0 +1,48 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/chip.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_MCX_NXXX_CHIP_H +#define __ARCH_ARM_SRC_MCX_NXXX_CHIP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifndef __ASSEMBLY__ +# include +# include +# include +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ARMV8M_PERIPHERAL_INTERRUPTS NXXX_IRQ_NEXTINT + +/**************************************************************************** + * Macro Definitions + ****************************************************************************/ + +#endif /* __ARCH_ARM_SRC_MCX_NXXX_CHIP_H */ diff --git a/arch/arm/src/mcx-nxxx/hardware/n236/n236_clock.h b/arch/arm/src/mcx-nxxx/hardware/n236/n236_clock.h new file mode 100644 index 0000000000000..99176a5d999c8 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/hardware/n236/n236_clock.h @@ -0,0 +1,728 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/hardware/n236/n236_clock.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_N236_N236_CLOCK_H +#define __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_N236_N236_CLOCK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Clock muxes */ + +#define SYSCON_SYSTICKCLKSEL0 (NXXX_SYSCON0_BASE + 0x260) +#define SYSCON_TRACECLKSEL (NXXX_SYSCON0_BASE + 0x268) +#define SYSCON_CTIMERCLKSEL0 (NXXX_SYSCON0_BASE + 0x26C) +#define SYSCON_CTIMERCLKSEL1 (NXXX_SYSCON0_BASE + 0x270) +#define SYSCON_CTIMERCLKSEL2 (NXXX_SYSCON0_BASE + 0x274) +#define SYSCON_CTIMERCLKSEL3 (NXXX_SYSCON0_BASE + 0x278) +#define SYSCON_CTIMERCLKSEL4 (NXXX_SYSCON0_BASE + 0x27C) +#define SYSCON_CLKOUTCLKSEL (NXXX_SYSCON0_BASE + 0x288) +#define SYSCON_ADC0CLKSEL (NXXX_SYSCON0_BASE + 0x2A4) +#define SYSCON_FCCLKSEL0 (NXXX_SYSCON0_BASE + 0x2B0) +#define SYSCON_FCCLKSEL1 (NXXX_SYSCON0_BASE + 0x2B4) +#define SYSCON_FCCLKSEL2 (NXXX_SYSCON0_BASE + 0x2B8) +#define SYSCON_FCCLKSEL3 (NXXX_SYSCON0_BASE + 0x2BC) +#define SYSCON_FCCLKSEL4 (NXXX_SYSCON0_BASE + 0x2C0) +#define SYSCON_FCCLKSEL5 (NXXX_SYSCON0_BASE + 0x2C4) +#define SYSCON_FCCLKSEL6 (NXXX_SYSCON0_BASE + 0x2C8) +#define SYSCON_FCCLKSEL7 (NXXX_SYSCON0_BASE + 0x2CC) +#define SYSCON_ADC1CLKSEL (NXXX_SYSCON0_BASE + 0x464) +#define SYSCON_PLLCLKDIVSEL (NXXX_SYSCON0_BASE + 0x52C) +#define SYSCON_I3C0FCLKSEL (NXXX_SYSCON0_BASE + 0x530) +#define SYSCON_MICFILFCLKSEL (NXXX_SYSCON0_BASE + 0x548) +#define SYSCON_FLEXIOCLKSEL (NXXX_SYSCON0_BASE + 0x560) +#define SYSCON_FLEXCAN0CLKSEL (NXXX_SYSCON0_BASE + 0x5A0) +#define SYSCON_FLEXCAN1CLKSEL (NXXX_SYSCON0_BASE + 0x5A8) +#define SYSCON_EWM0CLKSEL (NXXX_SYSCON0_BASE + 0x5D4) +#define SYSCON_WDT1CLKSEL (NXXX_SYSCON0_BASE + 0x5D8) +#define SYSCON_OSTIMERCLKSEL (NXXX_SYSCON0_BASE + 0x5E0) +#define SYSCON_CMP0FCLKSEL (NXXX_SYSCON0_BASE + 0x5F0) +#define SYSCON_CMP0RRCLKSEL (NXXX_SYSCON0_BASE + 0x5F8) +#define SYSCON_CMP1FCLKSEL (NXXX_SYSCON0_BASE + 0x600) +#define SYSCON_CMP1RRCLKSEL (NXXX_SYSCON0_BASE + 0x608) +#define SYSCON_UTICKCLKSEL (NXXX_SYSCON0_BASE + 0x878) +#define SYSCON_SAI0CLKSEL (NXXX_SYSCON0_BASE + 0x880) +#define SYSCON_SAI1CLKSEL (NXXX_SYSCON0_BASE + 0x884) +#define SYSCON_I3C1FCLKSEL (NXXX_SYSCON0_BASE + 0xB30) + +/* Clock dividers */ + +#define SYSCON_DIVSYSTICKCLK0 (NXXX_SYSCON0_BASE + 0x300) +#define SYSCON_DIVTRACECLK (NXXX_SYSCON0_BASE + 0x308) +#define SYSCON_DIVSLOWCLK (NXXX_SYSCON0_BASE + 0x378) +#define SYSCON_DIVAHBCLK (NXXX_SYSCON0_BASE + 0x380) +#define SYSCON_DIVCLKOUT (NXXX_SYSCON0_BASE + 0x384) +#define SYSCON_DIVFROHFCLK (NXXX_SYSCON0_BASE + 0x388) +#define SYSCON_DIVWDT0CLK (NXXX_SYSCON0_BASE + 0x38C) +#define SYSCON_DIVADC0CLK (NXXX_SYSCON0_BASE + 0x394) +#define SYSCON_DIVPLLCLK (NXXX_SYSCON0_BASE + 0x3C4) +#define SYSCON_DIVCTIMER0CLK (NXXX_SYSCON0_BASE + 0x3D0) +#define SYSCON_DIVCTIMER1CLK (NXXX_SYSCON0_BASE + 0x3D4) +#define SYSCON_DIVCTIMER2CLK (NXXX_SYSCON0_BASE + 0x3D8) +#define SYSCON_DIVCTIMER3CLK (NXXX_SYSCON0_BASE + 0x3DC) +#define SYSCON_DIVCTIMER4CLK (NXXX_SYSCON0_BASE + 0x3E0) +#define SYSCON_DIVPLL1CLK0 (NXXX_SYSCON0_BASE + 0x3E4) +#define SYSCON_DIVPLL1CLK1 (NXXX_SYSCON0_BASE + 0x3E8) +#define SYSCON_DIVUTICKCLK (NXXX_SYSCON0_BASE + 0x3F0) +#define SYSCON_DIVFRG (NXXX_SYSCON0_BASE + 0x3F4) +#define SYSCON_DIVADC1CLK (NXXX_SYSCON0_BASE + 0x468) +#define SYSCON_DIVI3C0FCLK (NXXX_SYSCON0_BASE + 0x540) +#define SYSCON_DIVMICFILFCLK (NXXX_SYSCON0_BASE + 0x54C) +#define SYSCON_DIVFLEXIOCLK (NXXX_SYSCON0_BASE + 0x564) +#define SYSCON_DIVFLEXCAN0CLK (NXXX_SYSCON0_BASE + 0x5A4) +#define SYSCON_DIVFLEXCAN1CLK (NXXX_SYSCON0_BASE + 0x5AC) +#define SYSCON_DIVWDT1CLK (NXXX_SYSCON0_BASE + 0x5DC) +#define SYSCON_DIVCMP0FCLK (NXXX_SYSCON0_BASE + 0x5F4) +#define SYSCON_DIVCMP0RRCLK (NXXX_SYSCON0_BASE + 0x5FC) +#define SYSCON_DIVCMP1FCLK (NXXX_SYSCON0_BASE + 0x604) +#define SYSCON_DIVCMP1RRCLK (NXXX_SYSCON0_BASE + 0x60C) +#define SYSCON_DIVFLEXCOM0CLK (NXXX_SYSCON0_BASE + 0x850) +#define SYSCON_DIVFLEXCOM1CLK (NXXX_SYSCON0_BASE + 0x854) +#define SYSCON_DIVFLEXCOM2CLK (NXXX_SYSCON0_BASE + 0x858) +#define SYSCON_DIVFLEXCOM3CLK (NXXX_SYSCON0_BASE + 0x85C) +#define SYSCON_DIVFLEXCOM4CLK (NXXX_SYSCON0_BASE + 0x860) +#define SYSCON_DIVFLEXCOM5CLK (NXXX_SYSCON0_BASE + 0x864) +#define SYSCON_DIVFLEXCOM6CLK (NXXX_SYSCON0_BASE + 0x868) +#define SYSCON_DIVFLEXCOM7CLK (NXXX_SYSCON0_BASE + 0x86C) +#define SYSCON_DIVSAI0CLK (NXXX_SYSCON0_BASE + 0x888) +#define SYSCON_DIVSAI1CLK (NXXX_SYSCON0_BASE + 0x88C) +#define SYSCON_DIVI3C1FCLK (NXXX_SYSCON0_BASE + 0xB40) + +#define SYSCON_CLKDIV_DIV_SHIFT (0) /* Bits 0-7: Clock divider value */ +#define SYSCON_CLKDIV_DIV_MASK (0x7 << SYSCON_CLKDIV_DIV_SHIFT) +#define SYSCON_CLKDIV_DIV(n) (((n) << SYSCON_CLKDIV_DIV_SHIFT) & SYSCON_CLKDIV_DIV_MASK) + +#define SYSCON_CLKDIV_RESET (1 << 29) /* Bit 29: Resets the divider counter */ +#define SYSCON_CLKDIV_HALT (1 << 30) /* Bit 30: Halts the divider counter */ +#define SYSCON_CLKDIV_STAB (1 << 31) /* Bit 31: Divider status flag */ + +/* Peripheral clock selection */ + +#define SYSCON_SYSTICKCLK0 PERIPH_CLOCK(SYSCON_SYSTICKCLKSEL0, SYSCON_DIVSYSTICKCLK0) +#define SYSCON_TRACECLK PERIPH_CLOCK(SYSCON_TRACECLKSEL, SYSCON_DIVTRACECLK) +#define SYSCON_CTIMERCLK0 PERIPH_CLOCK(SYSCON_CTIMERCLKSEL0, SYSCON_DIVCTIMER0CLK) +#define SYSCON_CTIMERCLK1 PERIPH_CLOCK(SYSCON_CTIMERCLKSEL1, SYSCON_DIVCTIMER1CLK) +#define SYSCON_CTIMERCLK2 PERIPH_CLOCK(SYSCON_CTIMERCLKSEL2, SYSCON_DIVCTIMER2CLK) +#define SYSCON_CTIMERCLK3 PERIPH_CLOCK(SYSCON_CTIMERCLKSEL3, SYSCON_DIVCTIMER3CLK) +#define SYSCON_CTIMERCLK4 PERIPH_CLOCK(SYSCON_CTIMERCLKSEL4, SYSCON_DIVCTIMER4CLK) +#define SYSCON_CLKOUTCLK PERIPH_CLOCK(SYSCON_CLKOUTCLKSEL, SYSCON_DIVCLKOUT) +#define SYSCON_ADC0CLK PERIPH_CLOCK(SYSCON_ADC0CLKSEL, SYSCON_DIVADC0CLK) +#define SYSCON_FCCLK0 PERIPH_CLOCK(SYSCON_FCCLKSEL0, SYSCON_DIVFLEXCOM0CLK) +#define SYSCON_FCCLK1 PERIPH_CLOCK(SYSCON_FCCLKSEL1, SYSCON_DIVFLEXCOM1CLK) +#define SYSCON_FCCLK2 PERIPH_CLOCK(SYSCON_FCCLKSEL2, SYSCON_DIVFLEXCOM2CLK) +#define SYSCON_FCCLK3 PERIPH_CLOCK(SYSCON_FCCLKSEL3, SYSCON_DIVFLEXCOM3CLK) +#define SYSCON_FCCLK4 PERIPH_CLOCK(SYSCON_FCCLKSEL4, SYSCON_DIVFLEXCOM4CLK) +#define SYSCON_FCCLK5 PERIPH_CLOCK(SYSCON_FCCLKSEL5, SYSCON_DIVFLEXCOM5CLK) +#define SYSCON_FCCLK6 PERIPH_CLOCK(SYSCON_FCCLKSEL6, SYSCON_DIVFLEXCOM6CLK) +#define SYSCON_FCCLK7 PERIPH_CLOCK(SYSCON_FCCLKSEL7, SYSCON_DIVFLEXCOM7CLK) +#define SYSCON_ADC1CLK PERIPH_CLOCK(SYSCON_ADC1CLKSEL, SYSCON_DIVADC1CLK) +#define SYSCON_PLLCLKDIV PERIPH_CLOCK(SYSCON_PLLCLKDIVSEL, SYSCON_DIVPLLCLK) +#define SYSCON_I3C0FCLK PERIPH_CLOCK(SYSCON_I3C0FCLKSEL, SYSCON_DIVI3C0FCLK) +#define SYSCON_MICFILFCLK PERIPH_CLOCK(SYSCON_MICFILFCLKSEL, SYSCON_DIVMICFILFCLK) +#define SYSCON_FLEXIOCLK PERIPH_CLOCK(SYSCON_FLEXIOCLKSEL, SYSCON_DIVFLEXIOCLK) +#define SYSCON_FLEXCAN0CLK PERIPH_CLOCK(SYSCON_FLEXCAN0CLKSEL, SYSCON_DIVFLEXCAN0CLK) +#define SYSCON_FLEXCAN1CLK PERIPH_CLOCK(SYSCON_FLEXCAN1CLKSEL, SYSCON_DIVFLEXCAN1CLK) +#define SYSCON_EWM0CLK PERIPH_CLOCK(SYSCON_EWM0CLKSEL, ) /* TODO */ +#define SYSCON_WDT1CLK PERIPH_CLOCK(SYSCON_WDT1CLKSEL, SYSCON_DIVWDT1CLK) +#define SYSCON_OSTIMERCLK PERIPH_CLOCK(SYSCON_OSTIMERCLKSEL, ) /* TODO */ +#define SYSCON_CMP0FCLK PERIPH_CLOCK(SYSCON_CMP0FCLKSEL, SYSCON_DIVCMP0FCLK) +#define SYSCON_CMP0RRCLK PERIPH_CLOCK(SYSCON_CMP0RRCLKSEL, SYSCON_DIVCMP0RRCLK) +#define SYSCON_CMP1FCLK PERIPH_CLOCK(SYSCON_CMP1FCLKSEL, SYSCON_DIVCMP1FCLK) +#define SYSCON_CMP1RRCLK PERIPH_CLOCK(SYSCON_CMP1RRCLKSEL, SYSCON_DIVCMP1RRCLK) +#define SYSCON_UTICKCLK PERIPH_CLOCK(SYSCON_UTICKCLKSEL, SYSCON_DIVUTICKCLK) +#define SYSCON_SAI0CLK PERIPH_CLOCK(SYSCON_SAI0CLKSEL, SYSCON_DIVSAI0CLK) +#define SYSCON_SAI1CLK PERIPH_CLOCK(SYSCON_SAI1CLKSEL, SYSCON_DIVSAI1CLK) +#define SYSCON_I3C1FCLK PERIPH_CLOCK(SYSCON_I3C1FCLKSEL, SYSCON_DIVI3C1FCLK) + +/* Clock source names */ + +#define CLK_IN_TO_MAIN_CLK 1 /* clk_in to MAIN_CLK */ +#define FRO12M_TO_MAIN_CLK 2 /* FRO_12M to MAIN_CLK */ +#define FRO_HF_TO_MAIN_CLK 3 /* FRO_HF to MAIN_CLK */ +#define XTAL32K2_TO_MAIN_CLK 4 /* xtal32k[2] to MAIN_CLK */ +#define PLL0_TO_MAIN_CLK 5 /* PLL0 to MAIN_CLK */ +#define PLL1_TO_MAIN_CLK 6 /* PLL1 to MAIN_CLK */ +#define USB_PLL_TO_MAIN_CLK 7 /* USBPLL to MAIN_CLK */ +#define NONE_TO_MAIN_CLK 15 /* NONE to MAIN_CLK */ + +#define SYSTICK_DIV0_TO_SYSTICK0 0 /* SYSTICK_DIV0 to SYSTICK0 */ +#define CLK_1M_TO_SYSTICK0 1 /* Clk1MHz to SYSTICK0 */ +#define LPOSC_TO_SYSTICK0 2 /* LPOscilla to r to SYSTICK0 */ +#define NONE_TO_SYSTICK0 7 /* NONE to SYSTICK0 */ + +#define TRACE_DIV_TO_TRACE 0 /* TRACE_DIV to TRACE */ +#define CLK_1M_TO_TRACE 1 /* Clk1MHz to TRACE */ +#define LPOSC_TO_TRACE 2 /* LPOscilla to r to TRACE */ +#define NONE_TO_TRACE 7 /* NONE to TRACE */ + +#define CLK_1M_TO_CTIMER0 0 /* CLK_1M to CTIMER0 */ +#define PLL0_TO_CTIMER0 1 /* PLL0 to CTIMER0 */ +#define PLL1_CLK0_TO_CTIMER0 2 /* PLL1_clk0 to CTIMER0 */ +#define FRO_HF_TO_CTIMER0 3 /* FRO_HF to CTIMER0 */ +#define FRO12M_TO_CTIMER0 4 /* FRO12MHz to CTIMER0 */ +#define SAI0_MCLK_IN_TO_CTIMER0 5 /* SAI0MCLKIN to CTIMER0 */ +#define LPOSC_TO_CTIMER0 6 /* LPOscilla to r to CTIMER0 */ +#define SAI1_MCLK_IN_TO_CTIMER0 8 /* SAI1MCLKIN to CTIMER0 */ +#define SAI0_TX_BCLK_TO_CTIMER0 9 /* SAI0TX_BCLK to CTIMER0 */ +#define SAI0_RX_BCLK_TO_CTIMER0 10 /* SAI0RX_BCLK to CTIMER0 */ +#define SAI1_TX_BCLK_TO_CTIMER0 11 /* SAI1TX_BCLK to CTIMER0 */ +#define SAI1_RX_BCLK_TO_CTIMER0 12 /* SAI1RX_BCLK to CTIMER0 */ +#define NONE_TO_CTIMER0 15 /* NONE to CTIMER0 */ + +#define CLK_1M_TO_CTIMER1 0 /* CLK_1M to CTIMER1 */ +#define PLL0_TO_CTIMER1 1 /* PLL0 to CTIMER1 */ +#define PLL1_CLK0_TO_CTIMER1 2 /* PLL1_clk0 to CTIMER1 */ +#define FRO_HF_TO_CTIMER1 3 /* FRO_HF to CTIMER1 */ +#define FRO12M_TO_CTIMER1 4 /* FRO12MHz to CTIMER1 */ +#define SAI0_MCLK_IN_TO_CTIMER1 5 /* SAI0MCLKIN to CTIMER1 */ +#define LPOSC_TO_CTIMER1 6 /* LPOscilla to r to CTIMER1 */ +#define SAI1_MCLK_IN_TO_CTIMER1 8 /* SAI1MCLKIN to CTIMER1 */ +#define SAI0_TX_BCLK_TO_CTIMER1 9 /* SAI0TX_BCLK to CTIMER1 */ +#define SAI0_RX_BCLK_TO_CTIMER1 10 /* SAI0RX_BCLK to CTIMER1 */ +#define SAI1_TX_BCLK_TO_CTIMER1 11 /* SAI1TX_BCLK to CTIMER1 */ +#define SAI1_RX_BCLK_TO_CTIMER1 12 /* SAI1RX_BCLK to CTIMER1 */ +#define NONE_TO_CTIMER1 15 /* NONE to CTIMER1 */ + +#define CLK_1M_TO_CTIMER2 0 /* CLK_1M to CTIMER2 */ +#define PLL0_TO_CTIMER2 1 /* PLL0 to CTIMER2 */ +#define PLL1_CLK0_TO_CTIMER2 2 /* PLL1_clk0 to CTIMER2 */ +#define FRO_HF_TO_CTIMER2 3 /* FRO_HF to CTIMER2 */ +#define FRO12M_TO_CTIMER2 4 /* FRO12MHz to CTIMER2 */ +#define SAI0_MCLK_IN_TO_CTIMER2 5 /* SAI0MCLKIN to CTIMER2 */ +#define LPOSC_TO_CTIMER2 6 /* LPOscilla to r to CTIMER2 */ +#define SAI1_MCLK_IN_TO_CTIMER2 8 /* SAI1MCLKIN to CTIMER2 */ +#define SAI0_TX_BCLK_TO_CTIMER2 9 /* SAI0TX_BCLK to CTIMER2 */ +#define SAI0_RX_BCLK_TO_CTIMER2 10 /* SAI0RX_BCLK to CTIMER2 */ +#define SAI1_TX_BCLK_TO_CTIMER2 11 /* SAI1TX_BCLK to CTIMER2 */ +#define SAI1_RX_BCLK_TO_CTIMER2 12 /* SAI1RX_BCLK to CTIMER2 */ +#define NONE_TO_CTIMER2 15 /* NONE to CTIMER2 */ + +#define CLK_1M_TO_CTIMER3 0 /* CLK_1M to CTIMER3 */ +#define PLL0_TO_CTIMER3 1 /* PLL0 to CTIMER3 */ +#define PLL1_CLK0_TO_CTIMER3 2 /* PLL1_clk0 to CTIMER3 */ +#define FRO_HF_TO_CTIMER3 3 /* FRO_HF to CTIMER3 */ +#define FRO12M_TO_CTIMER3 4 /* FRO12MHz to CTIMER3 */ +#define SAI0_MCLK_IN_TO_CTIMER3 5 /* SAI0MCLKIN to CTIMER3 */ +#define LPOSC_TO_CTIMER3 6 /* LPOscilla to r to CTIMER3 */ +#define SAI1_MCLK_IN_TO_CTIMER3 8 /* SAI1MCLKIN to CTIMER3 */ +#define SAI0_TX_BCLK_TO_CTIMER3 9 /* SAI0TX_BCLK to CTIMER3 */ +#define SAI0_RX_BCLK_TO_CTIMER3 10 /* SAI0RX_BCLK to CTIMER3 */ +#define SAI1_TX_BCLK_TO_CTIMER3 11 /* SAI1TX_BCLK to CTIMER3 */ +#define SAI1_RX_BCLK_TO_CTIMER3 12 /* SAI1RX_BCLK to CTIMER3 */ +#define NONE_TO_CTIMER3 15 /* NONE to CTIMER3 */ + +#define CLK_1M_TO_CTIMER4 0 /* CLK_1M to CTIMER4 */ +#define PLL0_TO_CTIMER4 1 /* PLL0 to CTIMER4 */ +#define PLL1_CLK0_TO_CTIMER4 2 /* PLL1_clk0 to CTIMER4 */ +#define FRO_HF_TO_CTIMER4 3 /* FRO_HF to CTIMER4 */ +#define FRO12M_TO_CTIMER4 4 /* FRO12MHz to CTIMER4 */ +#define SAI0_MCLK_IN_TO_CTIMER4 5 /* SAI0MCLKIN to CTIMER4 */ +#define LPOSC_TO_CTIMER4 6 /* LPOscilla to r to CTIMER4 */ +#define SAI1_MCLK_IN_TO_CTIMER4 8 /* SAI1MCLKIN to CTIMER4 */ +#define SAI0_TX_BCLK_TO_CTIMER4 9 /* SAI0TX_BCLK to CTIMER4 */ +#define SAI0_RX_BCLK_TO_CTIMER4 10 /* SAI0RX_BCLK to CTIMER4 */ +#define SAI1_TX_BCLK_TO_CTIMER4 11 /* SAI1TX_BCLK to CTIMER4 */ +#define SAI1_RX_BCLK_TO_CTIMER4 12 /* SAI1RX_BCLK to CTIMER4 */ +#define NONE_TO_CTIMER4 15 /* NONE to CTIMER4 */ + +#define MAIN_CLK_TO_CLKOUT 0 /* MAIN_CLK to CLKOUT */ +#define PLL0_TO_CLKOUT 1 /* PLL0 to CLKOUT */ +#define CLK_IN_TO_CLKOUT 2 /* Clk_in to CLKOUT */ +#define FRO_HF_TO_CLKOUT 3 /* FRO_HF to CLKOUT */ +#define FRO12M_TO_CLKOUT 4 /* FRO12MHz to CLKOUT */ +#define PLL1_CLK0_TO_CLKOUT 5 /* PLL1_clk0 to CLKOUT */ +#define LPOSC_TO_CLKOUT 6 /* LPOscilla to r to CLKOUT */ +#define USB_PLL_TO_CLKOUT 7 /* USB_PLL to CLKOUT */ +#define NONE_TO_CLKOUT 15 /* NONE to CLKOUT */ + +#define PLL0_TO_ADC0 1 /* PLL0 to ADC0 */ +#define FRO_HF_TO_ADC0 2 /* FRO_HF to ADC0 */ +#define FRO12M_TO_ADC0 3 /* FRO12MHz to ADC0 */ +#define CLK_IN_TO_ADC0 4 /* Clk_in to ADC0 */ +#define PLL1_CLK0_TO_ADC0 5 /* PLL1_clk0 to ADC0 */ +#define USB_PLL_TO_ADC0 6 /* USBPLL to ADC0 */ +#define NONE_TO_ADC0 7 /* NONE to ADC0 */ + +#define PLL_DIV_TO_FLEXCOMM0 1 /* PLL_DIV to FLEXCOMM0 */ +#define FRO12M_TO_FLEXCOMM0 2 /* FRO12M to FLEXCOMM0 */ +#define FRO_HF_DIV_TO_FLEXCOMM0 3 /* FRO_HF_DIV to FLEXCOMM0 */ +#define CLK_1M_TO_FLEXCOMM0 4 /* CLK_1MHz to FLEXCOMM0 */ +#define USB_PLL_TO_FLEXCOMM0 5 /* USB_PLL to FLEXCOMM0 */ +#define LPOSC_TO_FLEXCOMM0 6 /* LPOscilla to r to FLEXCOMM0 */ +#define NONE_TO_FLEXCOMM0 7 /* NONE to FLEXCOMM0 */ + +#define PLL_DIV_TO_FLEXCOMM1 1 /* PLL_DIV to FLEXCOMM1 */ +#define FRO12M_TO_FLEXCOMM1 2 /* FRO12M to FLEXCOMM1 */ +#define FRO_HF_DIV_TO_FLEXCOMM1 3 /* FRO_HF_DIV to FLEXCOMM1 */ +#define CLK_1M_TO_FLEXCOMM1 4 /* CLK_1MHz to FLEXCOMM1 */ +#define USB_PLL_TO_FLEXCOMM1 5 /* USB_PLL to FLEXCOMM1 */ +#define LPOSC_TO_FLEXCOMM1 6 /* LPOscilla to r to FLEXCOMM1 */ +#define NONE_TO_FLEXCOMM1 7 /* NONE to FLEXCOMM1 */ + +#define PLL_DIV_TO_FLEXCOMM2 1 /* PLL_DIV to FLEXCOMM2 */ +#define FRO12M_TO_FLEXCOMM2 2 /* FRO12M to FLEXCOMM2 */ +#define FRO_HF_DIV_TO_FLEXCOMM2 3 /* FRO_HF_DIV to FLEXCOMM2 */ +#define CLK_1M_TO_FLEXCOMM2 4 /* CLK_1MHz to FLEXCOMM2 */ +#define USB_PLL_TO_FLEXCOMM2 5 /* USB_PLL to FLEXCOMM2 */ +#define LPOSC_TO_FLEXCOMM2 6 /* LPOscilla to r to FLEXCOMM2 */ +#define NONE_TO_FLEXCOMM2 7 /* NONE to FLEXCOMM2 */ + +#define PLL_DIV_TO_FLEXCOMM3 1 /* PLL_DIV to FLEXCOMM3 */ +#define FRO12M_TO_FLEXCOMM3 2 /* FRO12M to FLEXCOMM3 */ +#define FRO_HF_DIV_TO_FLEXCOMM3 3 /* FRO_HF_DIV to FLEXCOMM3 */ +#define CLK_1M_TO_FLEXCOMM3 4 /* CLK_1MHz to FLEXCOMM3 */ +#define USB_PLL_TO_FLEXCOMM3 5 /* USB_PLL to FLEXCOMM3 */ +#define LPOSC_TO_FLEXCOMM3 6 /* LPOscilla to r to FLEXCOMM3 */ +#define NONE_TO_FLEXCOMM3 7 /* NONE to FLEXCOMM3 */ + +#define PLL_DIV_TO_FLEXCOMM4 1 /* PLL_DIV to FLEXCOMM4 */ +#define FRO12M_TO_FLEXCOMM4 2 /* FRO12M to FLEXCOMM4 */ +#define FRO_HF_DIV_TO_FLEXCOMM4 3 /* FRO_HF_DIV to FLEXCOMM4 */ +#define CLK_1M_TO_FLEXCOMM4 4 /* CLK_1MHz to FLEXCOMM4 */ +#define USB_PLL_TO_FLEXCOMM4 5 /* USB_PLL to FLEXCOMM4 */ +#define LPOSC_TO_FLEXCOMM4 6 /* LPOscilla to r to FLEXCOMM4 */ +#define NONE_TO_FLEXCOMM4 7 /* NONE to FLEXCOMM4 */ + +#define PLL_DIV_TO_FLEXCOMM5 1 /* PLL_DIV to FLEXCOMM5 */ +#define FRO12M_TO_FLEXCOMM5 2 /* FRO12M to FLEXCOMM5 */ +#define FRO_HF_DIV_TO_FLEXCOMM5 3 /* FRO_HF_DIV to FLEXCOMM5 */ +#define CLK_1M_TO_FLEXCOMM5 4 /* CLK_1MHz to FLEXCOMM5 */ +#define USB_PLL_TO_FLEXCOMM5 5 /* USB_PLL to FLEXCOMM5 */ +#define LPOSC_TO_FLEXCOMM5 6 /* LPOscilla to r to FLEXCOMM5 */ +#define NONE_TO_FLEXCOMM5 7 /* NONE to FLEXCOMM5 */ + +#define PLL_DIV_TO_FLEXCOMM6 1 /* PLL_DIV to FLEXCOMM6 */ +#define FRO12M_TO_FLEXCOMM6 2 /* FRO12M to FLEXCOMM6 */ +#define FRO_HF_DIV_TO_FLEXCOMM6 3 /* FRO_HF_DIV to FLEXCOMM6 */ +#define CLK_1M_TO_FLEXCOMM6 4 /* CLK_1MHz to FLEXCOMM6 */ +#define USB_PLL_TO_FLEXCOMM6 5 /* USB_PLL to FLEXCOMM6 */ +#define LPOSC_TO_FLEXCOMM6 6 /* LPOscilla to r to FLEXCOMM6 */ +#define NONE_TO_FLEXCOMM6 7 /* NONE to FLEXCOMM6 */ + +#define PLL_DIV_TO_FLEXCOMM7 1 /* PLL_DIV to FLEXCOMM7 */ +#define FRO12M_TO_FLEXCOMM7 2 /* FRO12M to FLEXCOMM7 */ +#define FRO_HF_DIV_TO_FLEXCOMM7 3 /* FRO_HF_DIV to FLEXCOMM7 */ +#define CLK_1M_TO_FLEXCOMM7 4 /* CLK_1MHz to FLEXCOMM7 */ +#define USB_PLL_TO_FLEXCOMM7 5 /* USB_PLL to FLEXCOMM7 */ +#define LPOSC_TO_FLEXCOMM7 6 /* LPOscilla to r to FLEXCOMM7 */ +#define NONE_TO_FLEXCOMM7 7 /* NONE to FLEXCOMM7 */ + +#define PLL0_TO_ADC1 1 /* PLL0 to ADC1 */ +#define FRO_HF_TO_ADC1 2 /* FRO_HF to ADC1 */ +#define FRO12M_TO_ADC1 3 /* FRO12M to ADC1 */ +#define CLK_IN_TO_ADC1 4 /* clk_in to ADC1 */ +#define PLL1_CLK0_TO_ADC1 5 /* PLL1_clk0 to ADC1 */ +#define USB_PLL_TO_ADC1 6 /* USBPLL to ADC1 */ +#define NONE_TO_ADC1 7 /* NONE to ADC1 */ + +#define PLL0_TO_PLLCLKDIV 0 /* PLL0 to PLLCLKDIV */ +#define PLL1_CLK0_TO_PLLCLKDIV 1 /* pll1_clk0 to PLLCLKDIV */ +#define NONE_TO_PLLCLKDIV 1 /* NONE to PLLCLKDIV */ + +#define PLL0_TO_I3C0FCLK 1 /* PLL0 to I3C0FCLK */ +#define FRO_HF_TO_I3C0FCLK 3 /* FRO_HF to I3C0FCLK */ +#define CLK_1M_TO_I3C0FCLK 4 /* CLK_1M to I3C0FCLK */ +#define PLL1_CLK0_TO_I3C0FCLK 5 /* PLL1_clk0 to I3C0FCLK */ +#define USB_PLL_TO_I3C0FCLK 6 /* USBPLL to I3C0FCLK */ +#define NONE_TO_I3C0FCLK 7 /* NONE to I3C0FCLK */ + +#define PLL0_TO_I3C0FCLKSTC 1 /* PLL0 to I3C0FCLKSTC */ +#define FRO_HF_TO_I3C0FCLKSTC 3 /* FRO_HF to I3C0FCLKSTC */ +#define CLK_1M_TO_I3C0FCLKSTC 4 /* CLK_1M to I3C0FCLKSTC */ +#define PLL1_CLK0_TO_I3C0FCLKSTC 5 /* PLL1_clk0 to I3C0FCLKSTC */ +#define USB_PLL_TO_I3C0FCLKSTC 6 /* USBPLL to I3C0FCLKSTC */ +#define NONE_TO_I3C0FCLKSTC 7 /* NONE to I3C0FCLKSTC */ + +#define PLL0_TO_I3C0FCLKSLOW 1 /* PLL0 to I3C0FCLKS */ +#define FRO_HF_TO_I3C0FCLKSLOW 3 /* FRO_HF to I3C0FCLKS */ +#define CLK_1M_TO_I3C0FCLKSLOW 4 /* CLK_1M to I3C0FCLKS */ +#define PLL1_CLK0_TO_I3C0FCLKSLOW 5 /* PLL1_clk0 to I3C0FCLKS */ +#define USB_PLL_TO_I3C0FCLKSLOW 6 /* USBPLL to I3C0FCLKS */ +#define NONE_TO_I3C0FCLKSLOW 7 /* NONE to I3C0FCLKS */ + +#define FRO12M_TO_MICFILF 0 /* FRO_12M to MICFILF */ +#define PLL0_TO_MICFILF 1 /* PLL0 to MICFILF */ +#define CLK_IN_TO_MICFILF 2 /* Clk_in to MICFILF */ +#define FRO_HF_TO_MICFILF 3 /* FRO_HF to MICFILF */ +#define PLL1_CLK0_TO_MICFILF 4 /* PLL1_clk0 to MICFILF */ +#define SAI0_MCLK_IN_TO_MICFILF 5 /* SAI0_MCLK to MICFILF */ +#define USB_PLL_TO_MICFILF 6 /* USBPLL to MICFILF */ +#define SAI1_MCLK_IN_TO_MICFILF 8 /* SAI1_MCLK to MICFILF */ +#define NONE_TO_MICFILF 15 /* NONE to MICFILF */ + +#define PLL0_TO_FLEXIO 1 /* PLL0 to FLEXIO */ +#define CLK_IN_TO_FLEXIO 2 /* Clk_in to FLEXIO */ +#define FRO_HF_TO_FLEXIO 3 /* FRO_HF to FLEXIO */ +#define FRO12M_TO_FLEXIO 4 /* FRO_12M to FLEXIO */ +#define PLL1_CLK0_TO_FLEXIO 5 /* pll1_clk0 to FLEXIO */ +#define USB_PLL_TO_FLEXIO 6 /* USBPLL to FLEXIO */ +#define NONE_TO_FLEXIO 7 /* NONE to FLEXIO */ + +#define PLL0_TO_FLEXCAN0 1 /* PLL0 to FLEXCAN0 */ +#define CLK_IN_TO_FLEXCAN0 2 /* Clk_in to FLEXCAN0 */ +#define FRO_HF_TO_FLEXCAN0 3 /* FRO_HF to FLEXCAN0 */ +#define PLL1_CLK0_TO_FLEXCAN0 5 /* pll1_clk0 to FLEXCAN0 */ +#define USB_PLL_TO_FLEXCAN0 6 /* USBPLL to FLEXCAN0 */ +#define NONE_TO_FLEXCAN0 7 /* NONE to FLEXCAN0 */ + +#define PLL0_TO_FLEXCAN1 1 /* PLL0 to FLEXCAN1 */ +#define CLK_IN_TO_FLEXCAN1 2 /* Clk_in to FLEXCAN1 */ +#define FRO_HF_TO_FLEXCAN1 3 /* FRO_HF to FLEXCAN1 */ +#define PLL1_CLK0_TO_FLEXCAN1 5 /* pll1_clk0 to FLEXCAN1 */ +#define USB_PLL_TO_FLEXCAN1 6 /* USBPLL to FLEXCAN1 */ +#define NONE_TO_FLEXCAN1 7 /* NONE to FLEXCAN1 */ + +#define CLK_16K2_TO_EWM0 0 /* clk_16k[2] to EWM0 */ +#define XTAL32K2_TO_EWM0 1 /* xtal32k[2] to EWM0 */ + +#define CLK_16K2_TO_WDT1 0 /* FRO16Kclock2 to WDT1 */ +#define FRO_HF_DIV_TO_WDT1 1 /* FRO_HF_DIV to WDT1 */ +#define CLK_1M_TO_WDT1 2 /* clk_1m to WDT1 */ +#define CLK_1M_2_TO_WDT1 3 /* clk_1m to WDT1 */ + +#define CLK_16K2_TO_OSTIMER 0 /* clk_16k[2] to OSTIMER */ +#define XTAL32K2_TO_OSTIMER 1 /* xtal32k[2] to OSTIMER */ +#define CLK_1M_TO_OSTIMER 2 /* clk_1m to OSTIMER */ +#define NONE_TO_OSTIMER 3 /* NONE to OSTIMER */ + +#define PLL0_TO_CMP0F 1 /* PLL0 to CMP0F */ +#define FRO_HF_TO_CMP0F 2 /* FRO_HF to CMP0F */ +#define FRO12M_TO_CMP0F 3 /* FRO_12M to CMP0F */ +#define CLK_IN_TO_CMP0F 4 /* Clk_in to CMP0F */ +#define PLL1_CLK0_TO_CMP0F 5 /* PLL1_clk0 to CMP0F */ +#define USB_PLL_TO_CMP0F 6 /* USBPLL to CMP0F */ +#define NONE_TO_CMP0F 7 /* NONE to CMP0F */ + +#define PLL0_TO_CMP0RR 1 /* PLL0 to CMP0RR */ +#define FRO_HF_TO_CMP0RR 2 /* FRO_HF to CMP0RR */ +#define FRO12M_TO_CMP0RR 3 /* FRO_12M to CMP0RR */ +#define CLK_IN_TO_CMP0RR 4 /* Clk_in to CMP0RR */ +#define PLL1_CLK0_TO_CMP0RR 5 /* PLL1_clk0 to CMP0RR */ +#define USB_PLL_TO_CMP0RR 6 /* USBPLL to CMP0RR */ +#define NONE_TO_CMP0RR 7 /* NONE to CMP0RR */ + +#define PLL0_TO_CMP1F 1 /* PLL0 to CMP1F */ +#define FRO_HF_TO_CMP1F 2 /* FRO_HF to CMP1F */ +#define FRO12M_TO_CMP1F 3 /* FRO_12M to CMP1F */ +#define CLK_IN_TO_CMP1F 4 /* Clk_in to CMP1F */ +#define PLL1_CLK0_TO_CMP1F 5 /* PLL1_clk0 to CMP1F */ +#define USB_PLL_TO_CMP1F 6 /* USBPLL to CMP1F */ +#define NONE_TO_CMP1F 7 /* NONE to CMP1F */ + +#define PLL0_TO_CMP1RR 1 /* PLL0 to CMP1RR */ +#define FRO_HF_TO_CMP1RR 2 /* FRO_HF to CMP1RR */ +#define FRO12M_TO_CMP1RR 3 /* FRO_12M to CMP1RR */ +#define CLK_IN_TO_CMP1RR 4 /* Clk_in to CMP1RR */ +#define PLL1_CLK0_TO_CMP1RR 5 /* PLL1_clk0 to CMP1RR */ +#define USB_PLL_TO_CMP1RR 6 /* USBPLL to CMP1RR */ +#define NONE_TO_CMP1RR 7 /* NONE to CMP1RR */ + +#define CLK_IN_TO_UTICK 0 /* Clk_in to UTICK */ +#define XTAL32K2_TO_UTICK 1 /* xtal32k[2] to UTICK */ +#define CLK_1M_TO_UTICK 2 /* clk_1m to UTICK */ +#define NONE_TO_UTICK 3 /* NONE to UTICK */ + +#define PLL0_TO_SAI0 1 /* PLL0 to SAI0 */ +#define CLK_IN_TO_SAI0 2 /* Clk_in to SAI0 */ +#define FRO_HF_TO_SAI0 3 /* FRO_HF to SAI0 */ +#define PLL1_CLK0_TO_SAI0 4 /* PLL1_clk0 to SAI0 */ +#define USB_PLL_TO_SAI0 6 /* USBPLL to SAI0 */ +#define NONE_TO_SAI0 7 /* NONE to SAI0 */ + +#define PLL0_TO_SAI1 1 /* PLL0 to SAI1 */ +#define CLK_IN_TO_SAI1 2 /* Clk_in to SAI1 */ +#define FRO_HF_TO_SAI1 3 /* FRO_HF to SAI1 */ +#define PLL1_CLK0_TO_SAI1 4 /* PLL1_clk0 to SAI1 */ +#define USB_PLL_TO_SAI1 6 /* USBPLL to SAI1 */ +#define NONE_TO_SAI1 7 /* NONE to SAI1 */ + +#define PLL0_TO_I3C1FCLK 1 /* PLL0 to I3C1FCLK */ +#define FRO_HF_TO_I3C1FCLK 3 /* FRO_HF to I3C1FCLK */ +#define CLK_1M_TO_I3C1FCLK 4 /* CLK_1M to I3C1FCLK */ +#define PLL1_CLK0_TO_I3C1FCLK 5 /* PLL1_clk0 to I3C1FCLK */ +#define USB_PLL_TO_I3C1FCLK 6 /* USBPLL to I3C1FCLK */ +#define NONE_TO_I3C1FCLK 7 /* NONE to I3C1FCLK */ + +#define PLL0_TO_I3C1FCLKSTC 1 /* PLL0 to I3C1FCLKSTC */ +#define FRO_HF_TO_I3C1FCLKSTC 3 /* FRO_HF to I3C1FCLKSTC */ +#define CLK_1M_TO_I3C1FCLKSTC 4 /* CLK_1M to I3C1FCLKSTC */ +#define PLL1_CLK0_TO_I3C1FCLKSTC 5 /* PLL1_clk0 to I3C1FCLKSTC */ +#define USB_PLL_TO_I3C1FCLKSTC 6 /* USBPLL to I3C1FCLKSTC */ +#define NONE_TO_I3C1FCLKSTC 7 /* NONE to I3C1FCLKSTC */ + +#define PLL0_TO_I3C1FCLKSLOW 1 /* PLL0 to I3C1FCLKS */ +#define FRO_HF_TO_I3C1FCLKSLOW 3 /* FRO_HF to I3C1FCLKS */ +#define CLK_1M_TO_I3C1FCLKSLOW 4 /* CLK_1M to I3C1FCLKS */ +#define PLL1_CLK0_TO_I3C1FCLKSLOW 5 /* PLL1_clk0 to I3C1FCLKS */ +#define USB_PLL_TO_I3C1FCLKSLOW 6 /* USBPLL to I3C1FCLKS */ +#define NONE_TO_I3C1FCLKSLOW 7 /* NONE to I3C1FCLKS */ + +/* Clock gate control */ + +#define AHB_CLK_CTRL0 (NXXX_SYSCON0_BASE + 0x200) +#define AHB_CLK_CTRL1 (NXXX_SYSCON0_BASE + 0x204) +#define AHB_CLK_CTRL2 (NXXX_SYSCON0_BASE + 0x208) +#define AHB_CLK_CTRL3 (NXXX_SYSCON0_BASE + 0x20C) + +#define AHB_CLK_CTRL_SET0 (NXXX_SYSCON0_BASE + 0x220) +#define AHB_CLK_CTRL_SET1 (NXXX_SYSCON0_BASE + 0x224) +#define AHB_CLK_CTRL_SET2 (NXXX_SYSCON0_BASE + 0x228) +#define AHB_CLK_CTRL_SET3 (NXXX_SYSCON0_BASE + 0x22C) + +#define AHB_CLK_CTRL_CLR0 (NXXX_SYSCON0_BASE + 0x240) +#define AHB_CLK_CTRL_CLR1 (NXXX_SYSCON0_BASE + 0x244) +#define AHB_CLK_CTRL_CLR2 (NXXX_SYSCON0_BASE + 0x248) +#define AHB_CLK_CTRL_CLR3 (NXXX_SYSCON0_BASE + 0x24C) + +/* Clock gates in SYSCON */ + +#define CLOCK_GATE_ROM CLOCK_GATE(AHB_CLK_CTRL0, 1) /* Rom */ +#define CLOCK_GATE_SRAM1 CLOCK_GATE(AHB_CLK_CTRL0, 2) /* Sram1 */ +#define CLOCK_GATE_SRAM2 CLOCK_GATE(AHB_CLK_CTRL0, 3) /* Sram2 */ +#define CLOCK_GATE_SRAM3 CLOCK_GATE(AHB_CLK_CTRL0, 4) /* Sram3 */ +#define CLOCK_GATE_SRAM4 CLOCK_GATE(AHB_CLK_CTRL0, 5) /* Sram4 */ +#define CLOCK_GATE_SRAM5 CLOCK_GATE(AHB_CLK_CTRL0, 6) /* Sram5 */ +#define CLOCK_GATE_SRAM6 CLOCK_GATE(AHB_CLK_CTRL0, 7) /* Sram6 */ +#define CLOCK_GATE_SRAM7 CLOCK_GATE(AHB_CLK_CTRL0, 8) /* Sram7 */ +#define CLOCK_GATE_FMU CLOCK_GATE(AHB_CLK_CTRL0, 9) /* Fmu */ +#define CLOCK_GATE_FMC CLOCK_GATE(AHB_CLK_CTRL0, 10) /* Fmc */ +#define CLOCK_GATE_FLEXSPI CLOCK_GATE(AHB_CLK_CTRL0, 11) /* Flexspi */ +#define CLOCK_GATE_INPUTMUX0 CLOCK_GATE(AHB_CLK_CTRL0, 12) /* InputMux0 */ +#define CLOCK_GATE_INPUTMUX CLOCK_GATE(AHB_CLK_CTRL0, 12) /* InputMux0 */ +#define CLOCK_GATE_PORT0 CLOCK_GATE(AHB_CLK_CTRL0, 13) /* Port0 */ +#define CLOCK_GATE_PORT1 CLOCK_GATE(AHB_CLK_CTRL0, 14) /* Port1 */ +#define CLOCK_GATE_PORT2 CLOCK_GATE(AHB_CLK_CTRL0, 15) /* Port2 */ +#define CLOCK_GATE_PORT3 CLOCK_GATE(AHB_CLK_CTRL0, 16) /* Port3 */ +#define CLOCK_GATE_PORT4 CLOCK_GATE(AHB_CLK_CTRL0, 17) /* Port4 */ +#define CLOCK_GATE_GPIO0 CLOCK_GATE(AHB_CLK_CTRL0, 19) /* Gpio0 */ +#define CLOCK_GATE_GPIO1 CLOCK_GATE(AHB_CLK_CTRL0, 20) /* Gpio1 */ +#define CLOCK_GATE_GPIO2 CLOCK_GATE(AHB_CLK_CTRL0, 21) /* Gpio2 */ +#define CLOCK_GATE_GPIO3 CLOCK_GATE(AHB_CLK_CTRL0, 22) /* Gpio3 */ +#define CLOCK_GATE_GPIO4 CLOCK_GATE(AHB_CLK_CTRL0, 23) /* Gpio4 */ +#define CLOCK_GATE_PINT CLOCK_GATE(AHB_CLK_CTRL0, 25) /* Pint */ +#define CLOCK_GATE_DMA0 CLOCK_GATE(AHB_CLK_CTRL0, 26) /* Dma0 */ +#define CLOCK_GATE_CRC0 CLOCK_GATE(AHB_CLK_CTRL0, 27) /* Crc */ +#define CLOCK_GATE_WWDT0 CLOCK_GATE(AHB_CLK_CTRL0, 28) /* Wwdt0 */ +#define CLOCK_GATE_WWDT1 CLOCK_GATE(AHB_CLK_CTRL0, 29) /* Wwdt1 */ +#define CLOCK_GATE_MAILBOX CLOCK_GATE(AHB_CLK_CTRL0, 31) /* Mailbox */ +#define CLOCK_GATE_MRT CLOCK_GATE(AHB_CLK_CTRL1, 0) /* Mrt */ +#define CLOCK_GATE_OSTIMER CLOCK_GATE(AHB_CLK_CTRL1, 1) /* OsTimer */ +#define CLOCK_GATE_SCT CLOCK_GATE(AHB_CLK_CTRL1, 2) /* Sct */ +#define CLOCK_GATE_ADC0 CLOCK_GATE(AHB_CLK_CTRL1, 3) /* Adc0 */ +#define CLOCK_GATE_ADC1 CLOCK_GATE(AHB_CLK_CTRL1, 4) /* Adc1 */ +#define CLOCK_GATE_DAC0 CLOCK_GATE(AHB_CLK_CTRL1, 5) /* Dac0 */ +#define CLOCK_GATE_RTC0 CLOCK_GATE(AHB_CLK_CTRL1, 6) /* Rtc */ +#define CLOCK_GATE_EVSIM0 CLOCK_GATE(AHB_CLK_CTRL1, 8) /* Evsim0 */ +#define CLOCK_GATE_EVSIM1 CLOCK_GATE(AHB_CLK_CTRL1, 9) /* Evsim1 */ +#define CLOCK_GATE_UTICK CLOCK_GATE(AHB_CLK_CTRL1, 10) /* Utick */ +#define CLOCK_GATE_LPFLEXCOMM0 CLOCK_GATE(AHB_CLK_CTRL1, 11) /* LPFlexComm0 */ +#define CLOCK_GATE_LPFLEXCOMM1 CLOCK_GATE(AHB_CLK_CTRL1, 12) /* LPFlexComm1 */ +#define CLOCK_GATE_LPFLEXCOMM2 CLOCK_GATE(AHB_CLK_CTRL1, 13) /* LPFlexComm2 */ +#define CLOCK_GATE_LPFLEXCOMM3 CLOCK_GATE(AHB_CLK_CTRL1, 14) /* LPFlexComm3 */ +#define CLOCK_GATE_LPFLEXCOMM4 CLOCK_GATE(AHB_CLK_CTRL1, 15) /* LPFlexComm4 */ +#define CLOCK_GATE_LPFLEXCOMM5 CLOCK_GATE(AHB_CLK_CTRL1, 16) /* LPFlexComm5 */ +#define CLOCK_GATE_LPFLEXCOMM6 CLOCK_GATE(AHB_CLK_CTRL1, 17) /* LPFlexComm6 */ +#define CLOCK_GATE_LPFLEXCOMM7 CLOCK_GATE(AHB_CLK_CTRL1, 18) /* LPFlexComm7 */ +#define CLOCK_GATE_LPFLEXCOMM8 CLOCK_GATE(AHB_CLK_CTRL1, 19) /* LPFlexComm8 */ +#define CLOCK_GATE_LPFLEXCOMM9 CLOCK_GATE(AHB_CLK_CTRL1, 20) /* LPFlexComm9 */ +#define CLOCK_GATE_LPUART0 CLOCK_GATE(AHB_CLK_CTRL1, 11) /* LPUart0 */ +#define CLOCK_GATE_LPUART1 CLOCK_GATE(AHB_CLK_CTRL1, 12) /* LPUart1 */ +#define CLOCK_GATE_LPUART2 CLOCK_GATE(AHB_CLK_CTRL1, 13) /* LPUart2 */ +#define CLOCK_GATE_LPUART3 CLOCK_GATE(AHB_CLK_CTRL1, 14) /* LPUart3 */ +#define CLOCK_GATE_LPUART4 CLOCK_GATE(AHB_CLK_CTRL1, 15) /* LPUart4 */ +#define CLOCK_GATE_LPUART5 CLOCK_GATE(AHB_CLK_CTRL1, 16) /* LPUart5 */ +#define CLOCK_GATE_LPUART6 CLOCK_GATE(AHB_CLK_CTRL1, 17) /* LPUart6 */ +#define CLOCK_GATE_LPUART7 CLOCK_GATE(AHB_CLK_CTRL1, 18) /* LPUart7 */ +#define CLOCK_GATE_LPUART8 CLOCK_GATE(AHB_CLK_CTRL1, 19) /* LPUart8 */ +#define CLOCK_GATE_LPUART9 CLOCK_GATE(AHB_CLK_CTRL1, 20) /* LPUart9 */ +#define CLOCK_GATE_LPSPI0 CLOCK_GATE(AHB_CLK_CTRL1, 11) /* LPSpi0 */ +#define CLOCK_GATE_LPSPI1 CLOCK_GATE(AHB_CLK_CTRL1, 12) /* LPSpi1 */ +#define CLOCK_GATE_LPSPI2 CLOCK_GATE(AHB_CLK_CTRL1, 13) /* LPSpi2 */ +#define CLOCK_GATE_LPSPI3 CLOCK_GATE(AHB_CLK_CTRL1, 14) /* LPSpi3 */ +#define CLOCK_GATE_LPSPI4 CLOCK_GATE(AHB_CLK_CTRL1, 15) /* LPSpi4 */ +#define CLOCK_GATE_LPSPI5 CLOCK_GATE(AHB_CLK_CTRL1, 16) /* LPSpi5 */ +#define CLOCK_GATE_LPSPI6 CLOCK_GATE(AHB_CLK_CTRL1, 17) /* LPSpi6 */ +#define CLOCK_GATE_LPSPI7 CLOCK_GATE(AHB_CLK_CTRL1, 18) /* LPSpi7 */ +#define CLOCK_GATE_LPSPI8 CLOCK_GATE(AHB_CLK_CTRL1, 19) /* LPSpi8 */ +#define CLOCK_GATE_LPSPI9 CLOCK_GATE(AHB_CLK_CTRL1, 20) /* LSpi9 */ +#define CLOCK_GATE_LPI2C0 CLOCK_GATE(AHB_CLK_CTRL1, 11) /* LPI2c0 */ +#define CLOCK_GATE_LPI2C1 CLOCK_GATE(AHB_CLK_CTRL1, 12) /* LPI2c1 */ +#define CLOCK_GATE_LPI2C2 CLOCK_GATE(AHB_CLK_CTRL1, 13) /* LPI2c2 */ +#define CLOCK_GATE_LPI2C3 CLOCK_GATE(AHB_CLK_CTRL1, 14) /* LPI2c3 */ +#define CLOCK_GATE_LPI2C4 CLOCK_GATE(AHB_CLK_CTRL1, 15) /* LPI2c4 */ +#define CLOCK_GATE_LPI2C5 CLOCK_GATE(AHB_CLK_CTRL1, 16) /* LPI2c5 */ +#define CLOCK_GATE_LPI2C6 CLOCK_GATE(AHB_CLK_CTRL1, 17) /* LPI2c6 */ +#define CLOCK_GATE_LPI2C7 CLOCK_GATE(AHB_CLK_CTRL1, 18) /* LPI2c7 */ +#define CLOCK_GATE_LPI2C8 CLOCK_GATE(AHB_CLK_CTRL1, 19) /* LPI2c8 */ +#define CLOCK_GATE_LPI2C9 CLOCK_GATE(AHB_CLK_CTRL1, 20) /* LPI2c9 */ +#define CLOCK_GATE_MICFIL CLOCK_GATE(AHB_CLK_CTRL1, 21) /* Micfil */ +#define CLOCK_GATE_TIMER2 CLOCK_GATE(AHB_CLK_CTRL1, 22) /* Timer2 */ +#define CLOCK_GATE_USB0RAM CLOCK_GATE(AHB_CLK_CTRL1, 23) /* Usb0Ram */ +#define CLOCK_GATE_USB0FSDCD CLOCK_GATE(AHB_CLK_CTRL1, 24) /* Usb0FsDcd */ +#define CLOCK_GATE_USB0FS CLOCK_GATE(AHB_CLK_CTRL1, 25) /* Usb0Fs */ +#define CLOCK_GATE_TIMER0 CLOCK_GATE(AHB_CLK_CTRL1, 26) /* Timer0 */ +#define CLOCK_GATE_TIMER1 CLOCK_GATE(AHB_CLK_CTRL1, 27) /* Timer1 */ +#define CLOCK_GATE_PKCRAM CLOCK_GATE(AHB_CLK_CTRL1, 29) /* PkcRam */ +#define CLOCK_GATE_SMARTDMA CLOCK_GATE(AHB_CLK_CTRL1, 31) /* SmartDma */ +#define CLOCK_GATE_ESPI CLOCK_GATE(AHB_CLK_CTRL2, 0) /* Espi */ +#define CLOCK_GATE_DMA1 CLOCK_GATE(AHB_CLK_CTRL2, 1) /* Dma1 */ +#define CLOCK_GATE_ENET CLOCK_GATE(AHB_CLK_CTRL2, 2) /* Enet */ +#define CLOCK_GATE_USDHC CLOCK_GATE(AHB_CLK_CTRL2, 3) /* uSdhc */ +#define CLOCK_GATE_FLEXIO CLOCK_GATE(AHB_CLK_CTRL2, 4) /* Flexio */ +#define CLOCK_GATE_SAI0 CLOCK_GATE(AHB_CLK_CTRL2, 5) /* Sai0 */ +#define CLOCK_GATE_SAI1 CLOCK_GATE(AHB_CLK_CTRL2, 6) /* Sai1 */ +#define CLOCK_GATE_TRO CLOCK_GATE(AHB_CLK_CTRL2, 7) /* Tro */ +#define CLOCK_GATE_FREQME CLOCK_GATE(AHB_CLK_CTRL2, 8) /* Freqme */ +#define CLOCK_GATE_TRNG CLOCK_GATE(AHB_CLK_CTRL2, 13) /* Trng */ +#define CLOCK_GATE_FLEXCAN0 CLOCK_GATE(AHB_CLK_CTRL2, 14) /* Flexcan0 */ +#define CLOCK_GATE_FLEXCAN1 CLOCK_GATE(AHB_CLK_CTRL2, 15) /* Flexcan1 */ +#define CLOCK_GATE_USBHS CLOCK_GATE(AHB_CLK_CTRL2, 16) /* UsbHs */ +#define CLOCK_GATE_USBHSPHY CLOCK_GATE(AHB_CLK_CTRL2, 17) /* UsbHsPhy */ +#define CLOCK_GATE_CSS CLOCK_GATE(AHB_CLK_CTRL2, 18) /* Css */ +#define CLOCK_GATE_POWERQUAD CLOCK_GATE(AHB_CLK_CTRL2, 19) /* PowerQuad */ +#define CLOCK_GATE_PLULUT CLOCK_GATE(AHB_CLK_CTRL2, 20) /* PluLut */ +#define CLOCK_GATE_TIMER3 CLOCK_GATE(AHB_CLK_CTRL2, 21) /* Timer3 */ +#define CLOCK_GATE_TIMER4 CLOCK_GATE(AHB_CLK_CTRL2, 22) /* Timer4 */ +#define CLOCK_GATE_PUF CLOCK_GATE(AHB_CLK_CTRL2, 23) /* Puf */ +#define CLOCK_GATE_PKC CLOCK_GATE(AHB_CLK_CTRL2, 24) /* Pkc */ +#define CLOCK_GATE_SCG CLOCK_GATE(AHB_CLK_CTRL2, 26) /* Scg */ +#define CLOCK_GATE_GDET CLOCK_GATE(AHB_CLK_CTRL2, 29) /* Gdet */ +#define CLOCK_GATE_SM3 CLOCK_GATE(AHB_CLK_CTRL2, 30) /* Sm3 */ +#define CLOCK_GATE_I3C0 CLOCK_GATE(AHB_CLK_CTRL3, 0) /* I3c0 */ +#define CLOCK_GATE_I3C1 CLOCK_GATE(AHB_CLK_CTRL3, 1) /* I3c1 */ +#define CLOCK_GATE_SINC CLOCK_GATE(AHB_CLK_CTRL3, 2) /* Sinc */ +#define CLOCK_GATE_COOLFLUX CLOCK_GATE(AHB_CLK_CTRL3, 3) /* CoolFlux */ +#define CLOCK_GATE_QDC0 CLOCK_GATE(AHB_CLK_CTRL3, 4) /* Qdc0 */ +#define CLOCK_GATE_QDC1 CLOCK_GATE(AHB_CLK_CTRL3, 5) /* Qdc1 */ +#define CLOCK_GATE_PWM0 CLOCK_GATE(AHB_CLK_CTRL3, 6) /* Pwm0 */ +#define CLOCK_GATE_PWM1 CLOCK_GATE(AHB_CLK_CTRL3, 7) /* Pwm1 */ +#define CLOCK_GATE_EVTG CLOCK_GATE(AHB_CLK_CTRL3, 8) /* Evtg */ +#define CLOCK_GATE_DAC1 CLOCK_GATE(AHB_CLK_CTRL3, 11) /* Dac1 */ +#define CLOCK_GATE_DAC2 CLOCK_GATE(AHB_CLK_CTRL3, 12) /* Dac2 */ +#define CLOCK_GATE_OPAMP0 CLOCK_GATE(AHB_CLK_CTRL3, 13) /* Opamp0 */ +#define CLOCK_GATE_OPAMP1 CLOCK_GATE(AHB_CLK_CTRL3, 14) /* Opamp1 */ +#define CLOCK_GATE_OPAMP2 CLOCK_GATE(AHB_CLK_CTRL3, 15) /* Opamp2 */ +#define CLOCK_GATE_CMP2 CLOCK_GATE(AHB_CLK_CTRL3, 18) /* Cmp2 */ +#define CLOCK_GATE_VREF CLOCK_GATE(AHB_CLK_CTRL3, 19) /* Vref */ +#define CLOCK_GATE_COOLFLUXAPB CLOCK_GATE(AHB_CLK_CTRL3, 20) /* CoolFluxApb */ +#define CLOCK_GATE_NEUTRON CLOCK_GATE(AHB_CLK_CTRL3, 21) /* Neutron */ +#define CLOCK_GATE_TSI CLOCK_GATE(AHB_CLK_CTRL3, 22) /* Tsi */ +#define CLOCK_GATE_EWM CLOCK_GATE(AHB_CLK_CTRL3, 23) /* Ewm */ +#define CLOCK_GATE_EWM0 CLOCK_GATE(AHB_CLK_CTRL3, 23) /* Ewm */ +#define CLOCK_GATE_EIM CLOCK_GATE(AHB_CLK_CTRL3, 24) /* Eim */ +#define CLOCK_GATE_ERM CLOCK_GATE(AHB_CLK_CTRL3, 25) /* Erm */ +#define CLOCK_GATE_INTM CLOCK_GATE(AHB_CLK_CTRL3, 26) /* Intm */ +#define CLOCK_GATE_SEMA42 CLOCK_GATE(AHB_CLK_CTRL3, 27) /* Sema42 */ +#define CLOCK_GATE_PWM0_SM0 CLOCK_GATE(REG_PWM0SUBCTL, 0U) /* PWM0 SM0 */ +#define CLOCK_GATE_PWM0_SM1 CLOCK_GATE(REG_PWM0SUBCTL, 1U) /* PWM0 SM1 */ +#define CLOCK_GATE_PWM0_SM2 CLOCK_GATE(REG_PWM0SUBCTL, 2U) /* PWM0 SM2 */ +#define CLOCK_GATE_PWM0_SM3 CLOCK_GATE(REG_PWM0SUBCTL, 3U) /* PWM0 SM3 */ +#define CLOCK_GATE_PWM1_SM0 CLOCK_GATE(REG_PWM1SUBCTL, 0U) /* PWM1 SM0 */ +#define CLOCK_GATE_PWM1_SM1 CLOCK_GATE(REG_PWM1SUBCTL, 1U) /* PWM1 SM1 */ +#define CLOCK_GATE_PWM1_SM2 CLOCK_GATE(REG_PWM1SUBCTL, 2U) /* PWM1 SM2 */ +#define CLOCK_GATE_PWM1_SM3 CLOCK_GATE(REG_PWM1SUBCTL, 3U) /* PWM1 SM3 */ + +/* Miscellaneous SYSCON registers */ + +/* LPCAC Control */ + +#define SYSCON_LPCAC_CTRL (NXXX_SYSCON0_BASE + 0x824) + +#define SYSCON_LPCAC_CTRL_DIS_LPCAC_SHIFT (0) +#define SYSCON_LPCAC_CTRL_DIS_LPCAC_MASK (0x01 << SYSCON_LPCAC_CTRL_DIS_LPCAC_SHIFT) +#define SYSCON_LPCAC_CTRL_DIS_LPCAC(x) (((x) << SYSCON_LPCAC_CTRL_DIS_LPCAC_SHIFT) & SYSCON_LPCAC_CTRL_DIS_LPCAC_MASK) + +#define SYSCON_LPCAC_CTRL_CLR_LPCAC_SHIFT (1) +#define SYSCON_LPCAC_CTRL_CLR_LPCAC_MASK (0x01 << SYSCON_LPCAC_CTRL_CLR_LPCAC_SHIFT) +#define SYSCON_LPCAC_CTRL_CLR_LPCAC(x) (((x) << SYSCON_LPCAC_CTRL_CLR_LPCAC_SHIFT) & SYSCON_LPCAC_CTRL_CLR_LPCAC_MASK) + +#define SYSCON_LPCAC_CTRL_FRC_NO_ALLOC_SHIFT (2) +#define SYSCON_LPCAC_CTRL_FRC_NO_ALLOC_MASK (0x01 << SYSCON_LPCAC_CTRL_FRC_NO_ALLOC_SHIFT) +#define SYSCON_LPCAC_CTRL_FRC_NO_ALLOC(x) (((x) << SYSCON_LPCAC_CTRL_FRC_NO_ALLOC_SHIFT) & SYSCON_LPCAC_CTRL_FRC_NO_ALLOC_MASK) + +#define SYSCON_LPCAC_CTRL_PARITY_MISS_EN_SHIFT (3) +#define SYSCON_LPCAC_CTRL_PARITY_MISS_EN_MASK (0x01 << SYSCON_LPCAC_CTRL_PARITY_MISS_EN_SHIFT) +#define SYSCON_LPCAC_CTRL_PARITY_MISS_EN(x) (((x) << SYSCON_LPCAC_CTRL_PARITY_MISS_EN_SHIFT) & SYSCON_LPCAC_CTRL_PARITY_MISS_EN_MASK) + +#define SYSCON_LPCAC_CTRL_DIS_LPCAC_WTBF_SHIFT (4) +#define SYSCON_LPCAC_CTRL_DIS_LPCAC_WTBF_MASK (0x01 << SYSCON_LPCAC_CTRL_DIS_LPCAC_WTBF_SHIFT) +#define SYSCON_LPCAC_CTRL_DIS_LPCAC_WTBF(x) (((x) << SYSCON_LPCAC_CTRL_DIS_LPCAC_WTBF_SHIFT) & SYSCON_LPCAC_CTRL_DIS_LPCAC_WTBF_MASK) + +#define SYSCON_LPCAC_CTRL_LIM_LPCAC_WTBF_SHIFT (5) +#define SYSCON_LPCAC_CTRL_LIM_LPCAC_WTBF_MASK (0x01 << SYSCON_LPCAC_CTRL_LIM_LPCAC_WTBF_SHIFT) +#define SYSCON_LPCAC_CTRL_LIM_LPCAC_WTBF(x) (((x) << SYSCON_LPCAC_CTRL_LIM_LPCAC_WTBF_SHIFT) & SYSCON_LPCAC_CTRL_LIM_LPCAC_WTBF_MASK) + +#define SYSCON_LPCAC_CTRL_PARITY_FAULT_EN_SHIFT (6) +#define SYSCON_LPCAC_CTRL_PARITY_FAULT_EN_MASK (0x01 << SYSCON_LPCAC_CTRL_PARITY_FAULT_EN_SHIFT) +#define SYSCON_LPCAC_CTRL_PARITY_FAULT_EN(x) (((x) << SYSCON_LPCAC_CTRL_PARITY_FAULT_EN_SHIFT) & SYSCON_LPCAC_CTRL_PARITY_FAULT_EN_MASK) + +#define SYSCON_LPCAC_CTRL_LPCAC_XOM_SHIFT (7) +#define SYSCON_LPCAC_CTRL_LPCAC_XOM_MASK (0x01 << SYSCON_LPCAC_CTRL_LPCAC_XOM_SHIFT) +#define SYSCON_LPCAC_CTRL_LPCAC_XOM(x) (((x) << SYSCON_LPCAC_CTRL_LPCAC_XOM_SHIFT) & SYSCON_LPCAC_CTRL_LPCAC_XOM_MASK) + +/* RAM ECC Enable Control */ + +#define SYSCON_ECC_ENABLE_CTRL (NXXX_SYSCON0_BASE + 0xe44) + +#define SYSCON_ECC_ENABLE_CTRL_RAMA_ECC_ENABLE (1 << 0) /* RAMA ECC enable */ +#define SYSCON_ECC_ENABLE_CTRL_RAMB_RAMX_ECC_ENABLE (1 << 1) /* RAMB and RAMX ECC enable */ +#define SYSCON_ECC_ENABLE_CTRL_RAMD_RAMC_ECC_ENABLE (1 << 2) /* RAMD and RAMC ECC enable */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef enum +{ + CORESYSCLK = 0, /* Core / system clock */ + BUSCLK = 1, /* AHB Bus clock */ + SYSTICKCLK0 = 2, /* Systick clock 0 */ + CLOCKOUT = 3, /* CLOCKOUT */ + FRO12M = 4, /* FRO12M */ + CLK1M = 5, /* CLK1M */ + FROHF = 6, /* FRO48 / 144 */ + CLK48M = 7, /* CLK48M */ + CLK144M = 8, /* CLK144M */ + CLK16K0 = 9, /* CLK16K[0] */ + CLK16K1 = 10, /* CLK16K[1] */ + CLK16K2 = 11, /* CLK16K[2] */ + CLK16K3 = 12, /* CLK16K[3] */ + EXTCLK = 13, /* External clock */ + OSC32K0 = 14, /* OSC32K[0] */ + OSC32K1 = 15, /* OSC32K[1] */ + OSC32K2 = 16, /* OSC32K[2] */ + OSC32K3 = 17, /* OSC32K[3] */ + PLL0OUT = 18, /* PLL0 output */ + PLL1OUT = 19, /* PLL1 output */ + USBPLLOUT = 20, /* USBPLL output */ + LPOSC = 21, /* Low power oscillator */ + LDB_PLL_CLK = 38, +} clock_id_e; + +#endif /* __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_N236_N236_CLOCK_H */ diff --git a/arch/arm/src/mcx-nxxx/hardware/n236/n236_gpio.h b/arch/arm/src/mcx-nxxx/hardware/n236/n236_gpio.h new file mode 100644 index 0000000000000..f72c95d717d14 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/hardware/n236/n236_gpio.h @@ -0,0 +1,61 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/hardware/n236/n236_gpio.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_N236_N236_GPIO_H +#define __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_N236_N236_GPIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "hardware/n236/n236_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NXXX_GPIO_VERID_OFFSET (0x0000) /* Version ID */ +#define NXXX_GPIO_PARAM_OFFSET (0x0004) /* Parameter */ +#define NXXX_GPIO_LOCK_OFFSET (0x000c) /* Lock */ +#define NXXX_GPIO_PCNS_OFFSET (0x0010) /* Pin Control Nonsecure */ +#define NXXX_GPIO_ICNS_OFFSET (0x0014) /* Interrupt Control Nonsecure */ +#define NXXX_GPIO_PCNP_OFFSET (0x0018) /* Pin Control Nonprivilege */ +#define NXXX_GPIO_ICNP_OFFSET (0x001c) /* Interrupt Control Nonprivilege */ +#define NXXX_GPIO_PDOR_OFFSET (0x0040) /* Port Data Output */ +#define NXXX_GPIO_PSOR_OFFSET (0x0044) /* Port Set Output */ +#define NXXX_GPIO_PCOR_OFFSET (0x0048) /* Port Clear Output */ +#define NXXX_GPIO_PTOR_OFFSET (0x004c) /* Port Toggle Output */ +#define NXXX_GPIO_PDIR_OFFSET (0x0050) /* Port Data Input */ +#define NXXX_GPIO_PDDR_OFFSET (0x0054) /* Port Data Direction */ +#define NXXX_GPIO_PIDR_OFFSET (0x0058) /* Port Input Disable */ +#define NXXX_GPIO_P0DR_OFFSET (0x0060) /* Pin Data (0-31 at offsets of n * 4h) */ +#define NXXX_GPIO_ICR0_OFFSET (0x0080) /* Interrupt Control (0-31 at offsets of n * 4h) */ +#define NXXX_GPIO_GICLR_OFFSET (0x0100) /* Global Interrupt Control Low */ +#define NXXX_GPIO_GICHR_OFFSET (0x0104) /* Global Interrupt Control High */ +#define NXXX_GPIO_ISFR0_OFFSET (0x0120) /* Interrupt Status Flag */ +#define NXXX_GPIO_ISFR1_OFFSET (0x0124) /* Interrupt Status Flag */ + +#endif /* __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_N236_N236_GPIO_H */ diff --git a/arch/arm/src/mcx-nxxx/hardware/n236/n236_memorymap.h b/arch/arm/src/mcx-nxxx/hardware/n236/n236_memorymap.h new file mode 100644 index 0000000000000..213319fae286b --- /dev/null +++ b/arch/arm/src/mcx-nxxx/hardware/n236/n236_memorymap.h @@ -0,0 +1,159 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/hardware/n236/n236_memorymap.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_N236_N236_MEMORYMAP_H +#define __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_N236_N236_MEMORYMAP_H + +#define NXXX_ADC0_BASE (0x4010D000u) +#define NXXX_ADC1_BASE (0x4010E000u) +#define NXXX_AHBSC_BASE (0x40120000u) +#define NXXX_AHBSC_ALIAS1_BASE (0x40121000u) +#define NXXX_AHBSC_ALIAS2_BASE (0x40122000u) +#define NXXX_AHBSC_ALIAS3_BASE (0x40123000u) +#define NXXX_CAN0_BASE (0x400D4000u) +#define NXXX_CAN1_BASE (0x400D8000u) +#define NXXX_CDOG0_BASE (0x400BB000u) +#define NXXX_CDOG1_BASE (0x400BC000u) +#define NXXX_CMC0_BASE (0x40048000u) +#define NXXX_CRC0_BASE (0x400CB000u) +#define NXXX_CTIMER0_BASE (0x4000C000u) +#define NXXX_CTIMER1_BASE (0x4000D000u) +#define NXXX_CTIMER2_BASE (0x4000E000u) +#define NXXX_CTIMER3_BASE (0x4000F000u) +#define NXXX_CTIMER4_BASE (0x40010000u) +#define NXXX_TDET0_BASE (0x40058000u) +#define NXXX_DM0_BASE (0x400BD000u) +#define NXXX_DMA0_BASE (0x40080000u) +#define NXXX_DMA1_BASE (0x400A0000u) +#define NXXX_EIM0_BASE (0x4005B000u) +#define NXXX_ERM0_BASE (0x4005C000u) +#define NXXX_EVTG0_BASE (0x400D2000u) +#define NXXX_EWM0_BASE (0x400C0000u) +#define NXXX_FLEXIO0_BASE (0x40105000u) +#define NXXX_FMU0_BASE (0x40043000u) +#define NXXX_FMU0TEST_BASE (0x40043000u) +#define NXXX_FREQME0_BASE (0x40011000u) +#define NXXX_GDET0_BASE (0x40024000u) +#define NXXX_GDET1_BASE (0x40025000u) +#define NXXX_GPIO0_BASE (0x40096000u) +#define NXXX_GPIO0_ALIAS1_BASE (0x40097000u) +#define NXXX_GPIO1_BASE (0x40098000u) +#define NXXX_GPIO1_ALIAS1_BASE (0x40099000u) +#define NXXX_GPIO2_BASE (0x4009A000u) +#define NXXX_GPIO2_ALIAS1_BASE (0x4009B000u) +#define NXXX_GPIO3_BASE (0x4009C000u) +#define NXXX_GPIO3_ALIAS1_BASE (0x4009D000u) +#define NXXX_GPIO4_BASE (0x4009E000u) +#define NXXX_GPIO4_ALIAS1_BASE (0x4009F000u) +#define NXXX_GPIO5_BASE (0x40040000u) +#define NXXX_GPIO5_ALIAS1_BASE (0x40041000u) +#define NXXX_SAI0_BASE (0x40106000u) +#define NXXX_SAI1_BASE (0x40107000u) +#define NXXX_I3C0_BASE (0x40021000u) +#define NXXX_I3C1_BASE (0x40022000u) +#define NXXX_INPUTMUX0_BASE (0x40006000u) +#define NXXX_INTM0_BASE (0x4005D000u) +#define NXXX_ITRC0_BASE (0x40026000u) +#define NXXX_CMP0_BASE (0x40051000u) +#define NXXX_CMP1_BASE (0x40052000u) +#define NXXX_LPI2C0_BASE (0x40092800u) +#define NXXX_LPI2C1_BASE (0x40093800u) +#define NXXX_LPI2C2_BASE (0x40094800u) +#define NXXX_LPI2C3_BASE (0x40095800u) +#define NXXX_LPI2C4_BASE (0x400B4800u) +#define NXXX_LPI2C5_BASE (0x400B5800u) +#define NXXX_LPI2C6_BASE (0x400B6800u) +#define NXXX_LPI2C7_BASE (0x400B7800u) +#define NXXX_LPSPI0_BASE (0x40092000u) +#define NXXX_LPSPI1_BASE (0x40093000u) +#define NXXX_LPSPI2_BASE (0x40094000u) +#define NXXX_LPSPI3_BASE (0x40095000u) +#define NXXX_LPSPI4_BASE (0x400B4000u) +#define NXXX_LPSPI5_BASE (0x400B5000u) +#define NXXX_LPSPI6_BASE (0x400B6000u) +#define NXXX_LPSPI7_BASE (0x400B7000u) +#define NXXX_LPTMR0_BASE (0x4004A000u) +#define NXXX_LPTMR1_BASE (0x4004B000u) +#define NXXX_LPUART0_BASE (0x40092000u) +#define NXXX_LPUART1_BASE (0x40093000u) +#define NXXX_LPUART2_BASE (0x40094000u) +#define NXXX_LPUART3_BASE (0x40095000u) +#define NXXX_LPUART4_BASE (0x400B4000u) +#define NXXX_LPUART5_BASE (0x400B5000u) +#define NXXX_LPUART6_BASE (0x400B6000u) +#define NXXX_LPUART7_BASE (0x400B7000u) +#define NXXX_FLEXCOMM0_BASE (0x40092000u) +#define NXXX_FLEXCOMM1_BASE (0x40093000u) +#define NXXX_FLEXCOMM2_BASE (0x40094000u) +#define NXXX_FLEXCOMM3_BASE (0x40095000u) +#define NXXX_FLEXCOMM4_BASE (0x400B4000u) +#define NXXX_FLEXCOMM5_BASE (0x400B5000u) +#define NXXX_FLEXCOMM6_BASE (0x400B6000u) +#define NXXX_FLEXCOMM7_BASE (0x400B7000u) +#define NXXX_MRT0_BASE (0x40013000u) +#define NXXX_NPX0_BASE (0x400CC000u) +#define NXXX_OSTIMER0_BASE (0x40049000u) +#define NXXX_OTPC0_BASE (0x400C9000u) +#define NXXX_PDM_BASE (0x4010C000u) +#define NXXX_PINT0_BASE (0x40004000u) +#define NXXX_PKC0_BASE (0x4002B000u) +#define NXXX_PORT0_BASE (0x40116000u) +#define NXXX_PORT1_BASE (0x40117000u) +#define NXXX_PORT2_BASE (0x40118000u) +#define NXXX_PORT3_BASE (0x40119000u) +#define NXXX_PORT4_BASE (0x4011A000u) +#define NXXX_PORT5_BASE (0x40042000u) +#define NXXX_PUF_BASE (0x4002C000u) +#define NXXX_PUF_ALIAS1_BASE (0x4002D000u) +#define NXXX_PUF_ALIAS2_BASE (0x4002E000u) +#define NXXX_PUF_ALIAS3_BASE (0x4002F000u) +#define NXXX_PWM0_BASE (0x400CE000u) +#define NXXX_PWM1_BASE (0x400D0000u) +#define NXXX_QDC0_BASE (0x400CF000u) +#define NXXX_QDC1_BASE (0x400D1000u) +#define NXXX_RTC0_BASE (0x4004C000u) +#define NXXX_ELS_BASE (0x40054000u) +#define NXXX_ELS_ALIAS1_BASE (0x40055000u) +#define NXXX_ELS_ALIAS2_BASE (0x40056000u) +#define NXXX_ELS_ALIAS3_BASE (0x40057000u) +#define NXXX_SCG0_BASE (0x40044000u) +#define NXXX_SMARTDMA0_BASE (0x40033000u) +#define NXXX_SPC0_BASE (0x40045000u) +#define NXXX_SYSCON0_BASE (0x40000000u) +#define NXXX_CMX_PERFMON0_BASE (0x400C1000u) +#define NXXX_TRDC_BASE (0x400C7000u) +#define NXXX_USBHS1__USBC_BASE (0x4010B000u) +#define NXXX_USBHS1_PHY_DCD_BASE (0x4010A000u) +#define NXXX_USBHS1__USBNC_BASE (0x4010B200u) +#define NXXX_USBPHY_BASE (0x4010A000u) +#define NXXX_UTICK0_BASE (0x40012000u) +#define NXXX_VBAT0_BASE (0x40059000u) +#define NXXX_VREF0_BASE (0x40111000u) +#define NXXX_WUU0_BASE (0x40046000u) +#define NXXX_WWDT0_BASE (0x40016000u) +#define NXXX_WWDT1_BASE (0x40017000u) + +#endif /* __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_N236_N236_MEMORYMAP_H */ diff --git a/arch/arm/src/mcx-nxxx/hardware/nxxx_clock.h b/arch/arm/src/mcx-nxxx/hardware/nxxx_clock.h new file mode 100644 index 0000000000000..74c14af97d384 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/hardware/nxxx_clock.h @@ -0,0 +1,78 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/hardware/nxxx_clock.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_CCM_H +#define __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_CCM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "hardware/nxxx_memorymap.h" + +#if defined(CONFIG_ARCH_CHIP_N236) +# include "hardware/n236/n236_clock.h" +#else +# error Unrecognized NXXx architecture +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Peripheral clocks are controlled by SYSCON0.sel and SYSCON0.div */ + +#define PERIPH_CLOCK(_mux, _div) \ + (struct clock_regs_s) \ + { \ + .mux = (_mux), \ + .div = (_div), \ + } + +/* Clock gates are in SYSCON0.ahb_clk_ctrlX, one bit per clock source */ + +#define CLOCK_GATE(_reg, _bit) \ + (struct clock_gate_reg_s) \ + { \ + .reg = (_reg), \ + .bit = (_bit), \ + } + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct clock_gate_reg_s +{ + uint32_t reg; + uint32_t bit; +}; + +struct clock_regs_s +{ + uint32_t mux; + uint32_t div; +}; + +#endif /* __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_CCM_H_ */ diff --git a/arch/arm/src/mcx-nxxx/hardware/nxxx_flexcomm.h b/arch/arm/src/mcx-nxxx/hardware/nxxx_flexcomm.h new file mode 100644 index 0000000000000..2253664d376a3 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/hardware/nxxx_flexcomm.h @@ -0,0 +1,95 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/hardware/nxxx_flexcomm.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_FLEXCOMM_H +#define __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_FLEXCOMM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "hardware/nxxx_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register offsets *********************************************************/ + +#define NXXX_FLEXCOMM_PSELID_OFFSET 0x0ff8 /* Peripheral Select /Flexcomm Interface ID */ +#define NXXX_FLEXCOMM_PID_OFFSET 0x0ffc /* Peripheral identification register */ + +/* Register addresses *******************************************************/ + +#define NXXX_FLEXCOMM0_PSELID (NXXX_FLEXCOMM0_BASE + NXXX_FLEXCOMM_PSELID_OFFSET) +#define NXXX_FLEXCOMM0_PID (NXXX_FLEXCOMM0_BASE + NXXX_FLEXCOMM_PID_OFFSET) + +#define NXXX_FLEXCOMM1_PSELID (NXXX_FLEXCOMM1_BASE + NXXX_FLEXCOMM_PSELID_OFFSET) +#define NXXX_FLEXCOMM1_PID (NXXX_FLEXCOMM1_BASE + NXXX_FLEXCOMM_PID_OFFSET) + +#define NXXX_FLEXCOMM2_PSELID (NXXX_FLEXCOMM2_BASE + NXXX_FLEXCOMM_PSELID_OFFSET) +#define NXXX_FLEXCOMM2_PID (NXXX_FLEXCOMM2_BASE + NXXX_FLEXCOMM_PID_OFFSET) + +#define NXXX_FLEXCOMM3_PSELID (NXXX_FLEXCOMM3_BASE + NXXX_FLEXCOMM_PSELID_OFFSET) +#define NXXX_FLEXCOMM3_PID (NXXX_FLEXCOMM3_BASE + NXXX_FLEXCOMM_PID_OFFSET) + +#define NXXX_FLEXCOMM4_PSELID (NXXX_FLEXCOMM4_BASE + NXXX_FLEXCOMM_PSELID_OFFSET) +#define NXXX_FLEXCOMM4_PID (NXXX_FLEXCOMM4_BASE + NXXX_FLEXCOMM_PID_OFFSET) + +#define NXXX_FLEXCOMM5_PSELID (NXXX_FLEXCOMM5_BASE + NXXX_FLEXCOMM_PSELID_OFFSET) +#define NXXX_FLEXCOMM5_PID (NXXX_FLEXCOMM5_BASE + NXXX_FLEXCOMM_PID_OFFSET) + +#define NXXX_FLEXCOMM6_PSELID (NXXX_FLEXCOMM6_BASE + NXXX_FLEXCOMM_PSELID_OFFSET) +#define NXXX_FLEXCOMM6_PID (NXXX_FLEXCOMM6_BASE + NXXX_FLEXCOMM_PID_OFFSET) + +#define NXXX_FLEXCOMM7_PSELID (NXXX_FLEXCOMM7_BASE + NXXX_FLEXCOMM_PSELID_OFFSET) +#define NXXX_FLEXCOMM7_PID (NXXX_FLEXCOMM7_BASE + NXXX_FLEXCOMM_PID_OFFSET) + +/* Register bit definitions *************************************************/ + +/* Peripheral Select /Flexcomm Interface ID */ + +#define FLEXCOMM_PSELID_PERSEL_SHIFT (0) /* Bits 0-2: Peripheral Select */ +#define FLEXCOMM_PSELID_PERSEL_MASK (7 << FLEXCOMM_PSELID_PERSEL_SHIFT) +# define FLEXCOMM_PSELID_PERSEL_NONE (0 << FLEXCOMM_PSELID_PERSEL_SHIFT) /* No peripheral selected */ +# define FLEXCOMM_PSELID_PERSEL_USART (1 << FLEXCOMM_PSELID_PERSEL_SHIFT) /* USART function selected */ +# define FLEXCOMM_PSELID_PERSEL_SPI (2 << FLEXCOMM_PSELID_PERSEL_SHIFT) /* SPI function selected */ +# define FLEXCOMM_PSELID_PERSEL_I2C (3 << FLEXCOMM_PSELID_PERSEL_SHIFT) /* I2C function selected */ + +#define FLEXCOMM_PSELID_LOCK (1 << 3) /* Bit 3: Lock the peripheral select */ +#define FLEXCOMM_PSELID_USARTPRESENT (1 << 4) /* Bit 4: USART present indicator */ +#define FLEXCOMM_PSELID_SPIPRESENT (1 << 5) /* Bit 5: SPI present indicator */ +#define FLEXCOMM_PSELID_I2CPRESENT (1 << 6) /* Bit 6: I2C present indicator */ +#define FLEXCOMM_PSELID_ID_SHIFT (12) /* Bits 12-31: Flexcomm Interface ID */ +#define FLEXCOMM_PSELID_ID_MASK (0xfffff << FLEXCOMM_PSELID_ID_SHIFT) + +/* Peripheral identification register */ + +#define FLEXCOMM_PID_MINOR_SHIFT (8) /* Bits 8-11: Minor revision number */ +#define FLEXCOMM_PID_MINOR_MASK (15 << FLEXCOMM_PID_MINOR_SHIFT) +#define FLEXCOMM_PID_MAJOR_SHIFT (12) /* Bits 12-15: Major revision number */ +#define FLEXCOMM_PID_MAJOR_MASK (15 << FLEXCOMM_PID_MAJOR_SHIFT) +#define FLEXCOMM_PID_ID_SHIFT (16) /* Bits 15-31: Module ID for selected function */ +#define FLEXCOMM_PID_ID_MASK (0xffff << FLEXCOMM_PID_ID_SHIFT) + +#endif /* __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_FLEXCOMM_H */ diff --git a/arch/arm/src/mcx-nxxx/hardware/nxxx_fmu.h b/arch/arm/src/mcx-nxxx/hardware/nxxx_fmu.h new file mode 100644 index 0000000000000..8fc18da69a0a6 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/hardware/nxxx_fmu.h @@ -0,0 +1,144 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/hardware/nxxx_fmu.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_FMU_H +#define ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_FMU_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NXXX_FMU_FSTAT (NXXX_FMU0_BASE + 0x0000) /* Flash Status Register */ +#define NXXX_FMU_FCNFG (NXXX_FMU0_BASE + 0x0004) /* Flash Configuration Register */ +#define NXXX_FMU_FCTRL (NXXX_FMU0_BASE + 0x0008) /* Flash Control Register */ +#define NXXX_FMU_FCCOB0 (NXXX_FMU0_BASE + 0x0010) /* Flash Common Command Object Registers */ +#define NXXX_FMU_FCCOB1 (NXXX_FMU0_BASE + 0x0014) /* Flash Common Command Object Registers */ +#define NXXX_FMU_FCCOB2 (NXXX_FMU0_BASE + 0x0018) /* Flash Common Command Object Registers */ +#define NXXX_FMU_FCCOB3 (NXXX_FMU0_BASE + 0x001C) /* Flash Common Command Object Registers */ +#define NXXX_FMU_FCCOB4 (NXXX_FMU0_BASE + 0x0020) /* Flash Common Command Object Registers */ +#define NXXX_FMU_FCCOB5 (NXXX_FMU0_BASE + 0x0024) /* Flash Common Command Object Registers */ +#define NXXX_FMU_FCCOB6 (NXXX_FMU0_BASE + 0x0028) /* Flash Common Command Object Registers */ +#define NXXX_FMU_FCCOB7 (NXXX_FMU0_BASE + 0x002C) /* Flash Common Command Object Registers */ + +/* Flash Status Register (FSTAT) */ + +#define FMU_FSTAT_FAIL_SHIFT (0) +#define FMU_FSTAT_FAIL_MASK (0x01 << FMU_FSTAT_FAIL_SHIFT) +#define FMU_FSTAT_FAIL(x) (((x) << FMU_FSTAT_FAIL_SHIFT) & FMU_FSTAT_FAIL_MASK) + +#define FMU_FSTAT_CMDABT_SHIFT (2) +#define FMU_FSTAT_CMDABT_MASK (0x01 << FMU_FSTAT_CMDABT_SHIFT) +#define FMU_FSTAT_CMDABT(x) (((x) << FMU_FSTAT_CMDABT_SHIFT) & FMU_FSTAT_CMDABT_MASK) + +#define FMU_FSTAT_PVIOL_SHIFT (4) +#define FMU_FSTAT_PVIOL_MASK (0x01 << FMU_FSTAT_PVIOL_SHIFT) +#define FMU_FSTAT_PVIOL(x) (((x) << FMU_FSTAT_PVIOL_SHIFT) & FMU_FSTAT_PVIOL_MASK) + +#define FMU_FSTAT_ACCERR_SHIFT (5) +#define FMU_FSTAT_ACCERR_MASK (0x01 << FMU_FSTAT_ACCERR_SHIFT) +#define FMU_FSTAT_ACCERR(x) (((x) << FMU_FSTAT_ACCERR_SHIFT) & FMU_FSTAT_ACCERR_MASK) + +#define FMU_FSTAT_CWSABT_SHIFT (6) +#define FMU_FSTAT_CWSABT_MASK (0x01 << FMU_FSTAT_CWSABT_SHIFT) +#define FMU_FSTAT_CWSABT(x) (((x) << FMU_FSTAT_CWSABT_SHIFT) & FMU_FSTAT_CWSABT_MASK) + +#define FMU_FSTAT_CCIF_SHIFT (7) +#define FMU_FSTAT_CCIF_MASK (0x01) +#define FMU_FSTAT_CCIF(x) (((x) << FMU_FSTAT_CCIF_SHIFT) & FMU_FSTAT_CCIF_MASK) + +#define FMU_FSTAT_CMDPRT_SHIFT (8) +#define FMU_FSTAT_CMDPRT_MASK (0x03 << FMU_FSTAT_CMDPRT_SHIFT) +#define FMU_FSTAT_CMDPRT(x) (((x) << FMU_FSTAT_CMDPRT_SHIFT) & FMU_FSTAT_CMDPRT_MASK) + +#define FMU_FSTAT_CMDP_SHIFT (11) +#define FMU_FSTAT_CMDP_MASK (0x01 << FMU_FSTAT_CMDP_SHIFT) +#define FMU_FSTAT_CMDP(x) (((x) << FMU_FSTAT_CMDP_SHIFT) & FMU_FSTAT_CMDP_MASK) + +#define FMU_FSTAT_CMDDID_SHIFT (12) +#define FMU_FSTAT_CMDDID_MASK (0x0f << FMU_FSTAT_CMDDID_SHIFT) +#define FMU_FSTAT_CMDDID(x) (((x) << FMU_FSTAT_CMDDID_SHIFT) & FMU_FSTAT_CMDDID_MASK) + +#define FMU_FSTAT_DFDIF_SHIFT (16) +#define FMU_FSTAT_DFDIF_MASK (0x01 << FMU_FSTAT_DFDIF_SHIFT) +#define FMU_FSTAT_DFDIF(x) (((x) << FMU_FSTAT_DFDIF_SHIFT) & FMU_FSTAT_DFDIF_MASK) + +#define FMU_FSTAT_SALV_USED_SHIFT (17) +#define FMU_FSTAT_SALV_USED_MASK (0x01 << FMU_FSTAT_SALV_USED_SHIFT) +#define FMU_FSTAT_SALV_USED(x) (((x) << FMU_FSTAT_SALV_USED_SHIFT) & FMU_FSTAT_SALV_USED_MASK) + +#define FMU_FSTAT_PEWEN_SHIFT (24) +#define FMU_FSTAT_PEWEN_MASK (0x03 << FMU_FSTAT_PEWEN_SHIFT) +#define FMU_FSTAT_PEWEN(x) (((x) << FMU_FSTAT_PEWEN_SHIFT) & FMU_FSTAT_PEWEN_MASK) + +#define FMU_FSTAT_PERDY_SHIFT (31) +#define FMU_FSTAT_PERDY_MASK (0x01 << FMU_FSTAT_PERDY_SHIFT) +#define FMU_FSTAT_PERDY(x) (((x) << FMU_FSTAT_PERDY_SHIFT) & FMU_FSTAT_PERDY_MASK) + +/* Flash Configuration Register (FCNFG) */ + +#define FMU_FCNFG_CCIE_SHIFT (7) +#define FMU_FCNFG_CCIE_MASK (0x01 << FMU_FCNFG_CCIE_SHIFT) +#define FMU_FCNFG_CCIE(x) (((x) << FMU_FCNFG_CCIE_SHIFT) & FMU_FCNFG_CCIE_MASK) + +#define FMU_FCNFG_ERSREQ_SHIFT (8) +#define FMU_FCNFG_ERSREQ_MASK (0x01 << FMU_FCNFG_ERSREQ_SHIFT) +#define FMU_FCNFG_ERSREQ(x) (((x) << FMU_FCNFG_ERSREQ_SHIFT) & FMU_FCNFG_ERSREQ_MASK) + +#define FMU_FCNFG_DFDIE_SHIFT (16) +#define FMU_FCNFG_DFDIE_MASK (0x01 << FMU_FCNFG_DFDIE_SHIFT) +#define FMU_FCNFG_DFDIE(x) (((x) << FMU_FCNFG_DFDIE_SHIFT) & FMU_FCNFG_DFDIE_MASK) + +#define FMU_FCNFG_ERSIEN0_SHIFT (24) +#define FMU_FCNFG_ERSIEN0_MASK (0x0f << FMU_FCNFG_ERSIEN0_SHIFT) +#define FMU_FCNFG_ERSIEN0(x) (((x) << FMU_FCNFG_ERSIEN0_SHIFT) & FMU_FCNFG_ERSIEN0_MASK) + +#define FMU_FCNFG_ERSIEN1_SHIFT (28) +#define FMU_FCNFG_ERSIEN1_MASK (0x0f << FMU_FCNFG_ERSIEN1_SHIFT) +#define FMU_FCNFG_ERSIEN1(x) (((x) << FMU_FCNFG_ERSIEN1_SHIFT) & FMU_FCNFG_ERSIEN1_MASK) + +/* Flash Control Register (FCTRL) */ + +#define FMU_FCTRL_RWSC_SHIFT (0) +#define FMU_FCTRL_RWSC_MASK (0x0f << FMU_FCTRL_RWSC_SHIFT) +#define FMU_FCTRL_RWSC(x) (((x) << FMU_FCTRL_RWSC_SHIFT) & FMU_FCTRL_RWSC_MASK) + +#define FMU_FCTRL_FDFD_SHIFT (16) +#define FMU_FCTRL_FDFD_MASK (0x01) +#define FMU_FCTRL_FDFD(x) (((x) << FMU_FCTRL_FDFD_SHIFT) & FMU_FCTRL_FDFD_MASK) + +#define FMU_FCTRL_ABTREQ_SHIFT (24) +#define FMU_FCTRL_ABTREQ_MASK (0x01) +#define FMU_FCTRL_ABTREQ(x) (((x) << FMU_FCTRL_ABTREQ_SHIFT) & FMU_FCTRL_ABTREQ_MASK) + +/* Flash Common Command Object Registers (FCCOB) */ + +#define FMU_FCCOB_CCOBn_SHIFT (0) +#define FMU_FCCOB_CCOBn_MASK (0xffffffff << FMU_FCCOB_CCOBn_SHIFT) +#define FMU_FCCOB_CCOBn(x) (((x) << FMU_FCCOB_CCOBn_SHIFT) & FMU_FCCOB_CCOBn_MASK) + +#endif /* ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_FMU_H */ diff --git a/arch/arm/src/mcx-nxxx/hardware/nxxx_gpio.h b/arch/arm/src/mcx-nxxx/hardware/nxxx_gpio.h new file mode 100644 index 0000000000000..b520072e7b980 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/hardware/nxxx_gpio.h @@ -0,0 +1,108 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/hardware/nxxx_gpio.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_GPIO_H +#define __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_GPIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#if defined(CONFIG_ARCH_CHIP_N236) +# include "hardware/n236/n236_gpio.h" +#else +# error Unrecognized NXXx architecture +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define GPIO1 0 /* Port 1 index */ +#define GPIO2 1 /* Port 2 index */ +#define GPIO3 2 /* Port 3 index */ +#define GPIO4 3 /* Port 4 index */ +#define GPIO5 4 /* Port 5 index */ +#define GPIO6 5 /* Port 6 index */ +#define GPIO7 6 /* Port 7 index */ +#define GPIO8 7 /* Port 8 index */ +#define GPIO9 8 /* Port 9 index */ +#define GPIO10 9 /* Port 10 index */ +#define GPIO11 10 /* Port 11 index */ +#define GPIO12 11 /* Port 12 index */ +#define GPIO13 12 /* Port 13 index */ + +#define NXXX_GPIO_NPINS 32 /* Up to 32 pins per port */ + +/* Register bit definitions *************************************************/ + +/* Most registers are laid out simply with one bit per pin */ + +#define GPIO_PIN(n) (1 << (n)) /* Bit n: Pin n, n=0-31 */ + +/* ICRN Register */ + +#define NXXX_GPIO_ICRN_ISF (1 << 24) /* Bit 24: Interrupt Status Flag */ +#define NXXX_GPIO_ICRN_LK (1 << 23) /* Bit 23: Lock Register */ +#define NXXX_GPIO_ICRN_IRQS (1 << 20) /* Bit 20: Configures the selected interrupt, or DMA request. */ +#define NXXX_GPIO_ICRN_SHIFT (16) /* Bits 16-19: Interrupt Configuration */ +#define NXXX_GPIO_ICRN_MASK (0xf << NXXX_GPIO_ICRN_SHIFT) +# define NXXX_GPIO_ICRN_DISABLED (0 << NXXX_GPIO_ICRN_SHIFT) /* Interrupt Status Flag (ISF) is disabled */ +# define NXXX_GPIO_ICRN_DMARISING (1 << NXXX_GPIO_ICRN_SHIFT) /* ISF flag and DMA request on rising edge */ +# define NXXX_GPIO_ICRN_DMAFALLING (2 << NXXX_GPIO_ICRN_SHIFT) /* ISF flag and DMA request on falling edge */ +# define NXXX_GPIO_ICRN_DMABOTH (3 << NXXX_GPIO_ICRN_SHIFT) /* ISF flag and DMA request on either edge */ +# define NXXX_GPIO_ICRN_ISFRISING (5 << NXXX_GPIO_ICRN_SHIFT) /* ISF flag sets on rising edge */ +# define NXXX_GPIO_ICRN_ISFFALLING (6 << NXXX_GPIO_ICRN_SHIFT) /* ISF flag sets on falling edge */ +# define NXXX_GPIO_ICRN_ISFBOTH (7 << NXXX_GPIO_ICRN_SHIFT) /* ISF flag sets on either edge */ +# define NXXX_GPIO_ICRN_ZERO (8 << NXXX_GPIO_ICRN_SHIFT) /* ISF flag and Interrupt when logic 0 */ +# define NXXX_GPIO_ICRN_RISING (9 << NXXX_GPIO_ICRN_SHIFT) /* ISF flag and Interrupt on rising-edge */ +# define NXXX_GPIO_ICRN_FALLING (10 << NXXX_GPIO_ICRN_SHIFT) /* ISF flag and Interrupt on falling-edge */ +# define NXXX_GPIO_ICRN_BOTH (11 << NXXX_GPIO_ICRN_SHIFT) /* ISF flag and Interrupt on either edge */ +# define NXXX_GPIO_ICRN_ONE (12 << NXXX_GPIO_ICRN_SHIFT) /* ISF flag and Interrupt when logic 1 */ + +/* Global Interrupt Control Low Register */ + +#define NXXX_GPIO_GICLR_GIWD_SHIFT (0) /* Bits 0-15: Global Interrupt Write Data */ +#define NXXX_GPIO_GICLR_GIWD_MASK (0xffff << NXXX_GPIO_GICLR_GIWD_SHIFT) +# define NXXX_GPIO_GICLR_GIWD_PIN(n) ((uint32_t)(n) << NXXX_GPIO_GICLR_GIWD_SHIFT) /* Pin n=0..15 */ + +#define NXXX_GPIO_GICLR_GIWE_SHIFT (16) /* Bits 16-31: Global Interrupt Write Enable */ +#define NXXX_GPIO_GICLR_GIWE_MASK (0xffff << NXXX_GPIO_GICLR_GIWE_SHIFT) +# define NXXX_GPIO_GICLR_GIWE_PIN(n) ((uint32_t)(n) << NXXX_GPIO_GICLR_GIWE_SHIFT) /* Pin n=0..15 */ + +/* Global Interrupt Control High Register */ + +#define NXXX_GPIO_GICHR_GIWD_SHIFT (0) /* Bits 0-15: Global Interrupt Write Data */ +#define NXXX_GPIO_GICHR_GIWD_MASK (0xffff << NXXX_GPIO_GICHR_GIWD_SHIFT) +# define NXXX_GPIO_GICHR_GIWD_PIN(n) ((uint32_t)((n) - 16) << NXXX_GPIO_GICHR_GIWD_SHIFT) /* Pin n=16..31 */ + +#define NXXX_GPIO_GICHR_GIWE_SHIFT (16) /* Bits 16-31: Global Interrupt Write Enable */ +#define NXXX_GPIO_GICHR_GIWE_MASK (0xffff << NXXX_GPIO_GICHR_GIWE_SHIFT) +# define NXXX_GPIO_GICHR_GIWE_PIN(n) ((uint32_t)((n) - 16) << NXXX_GPIO_GICHR_GIWE_SHIFT) /* Pin n=16..31 */ + +/* Interrupt Status Flag Register */ + +#define NXXX_GPIO_ISFR(n) (1 << (n)) /* Interrupt Status Flag, n=0-31 */ + +#endif /* __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_GPIO_H */ diff --git a/arch/arm/src/mcx-nxxx/hardware/nxxx_lpuart.h b/arch/arm/src/mcx-nxxx/hardware/nxxx_lpuart.h new file mode 100644 index 0000000000000..2e7b085aa5bbf --- /dev/null +++ b/arch/arm/src/mcx-nxxx/hardware/nxxx_lpuart.h @@ -0,0 +1,315 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/hardware/nxxx_lpuart.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_LPUART_H +#define __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_LPUART_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "hardware/nxxx_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* LPUART Register Offsets **************************************************/ + +#define NXXX_LPUART_VERID_OFFSET (0x00) /* Version ID Register (VERID) */ +#define NXXX_LPUART_PARAM_OFFSET (0x04) /* Parameter Register (PARAM) */ +#define NXXX_LPUART_GLOBAL_OFFSET (0x08) /* LPUART Global Register (GLOBAL) */ +#define NXXX_LPUART_PINCFG_OFFSET (0x0c) /* LPUART Pin Configuration Register (PINCFG) */ +#define NXXX_LPUART_BAUD_OFFSET (0x10) /* LPUART Baud Rate Register (BAUD) */ +#define NXXX_LPUART_STAT_OFFSET (0x14) /* LPUART Status Register (STAT) */ +#define NXXX_LPUART_CTRL_OFFSET (0x18) /* LPUART Control Register (CTRL) */ +#define NXXX_LPUART_DATA_OFFSET (0x1c) /* LPUART Data Register (DATA) */ +#define NXXX_LPUART_MATCH_OFFSET (0x20) /* LPUART Match Address Register (MATCH) */ +#define NXXX_LPUART_MODIR_OFFSET (0x24) /* LPUART Modem IrDA Register (MODIR) */ +#define NXXX_LPUART_FIFO_OFFSET (0x28) /* LPUART FIFO Register (FIFO) */ +#define NXXX_LPUART_WATER_OFFSET (0x2c) /* LPUART Watermark Register (WATER) */ +#define NXXX_LPUART_DATARO_OFFSET (0x30) /* Data read-only Register (DATARO) */ + +/* Register bit definitions *************************************************/ + +/* Version ID Register (VERID) */ + +#define LPUART_VERID_FEATURE_SHIFT (0) /* Bits 0-15: Feature Identification Number (FEATURE) */ +#define LPUART_VERID_FEATURE_MASK (0xffff << LPUART_VERID_FEATURE_SHIFT) +# define LPUART_VERID_FEATURE_STD (1 << LPUART_VERID_FEATURE_SHIFT) /* Standard feature set */ +# define LPUART_VERID_FEATURE_MODEM (3 << LPUART_VERID_FEATURE_SHIFT) /* MODEM/IrDA support */ + +#define LPUART_VERID_MINOR_SHIFT (16) /* Bits 16-23: Minor Version Number (MINOR) */ +#define LPUART_VERID_MINOR_MASK (0xff << LPUART_VERID_MINOR_SHIFT) +#define LPUART_VERID_MAJOR_SHIFT (24) /* Bits 24-31: Major Version Number (MAJOR) */ +#define LPUART_VERID_MAJOR_MASK (0xff << LPUART_VERID_MAJOR_SHIFT) + +/* Parameter Register (PARAM) */ + +#define LPUART_PARAM_TXFIFO_SHIFT (0) /* Bits 0-7: Transmit FIFO Size (TXFIFO) */ +#define LPUART_PARAM_TXFIFO_MASK (0xff << LPUART_PARAM_TXFIFO_SHIFT) +#define LPUART_PARAM_RXFIFO_SHIFT (8) /* Bits 8-15: Receive FIFO Size (RXFIFO) */ +#define LPUART_PARAM_RXFIFO_MASK (0xff << LPUART_PARAM_RXFIFO_SHIFT) + /* Bits 16-31: Reserved */ + +/* LPUART Global Register (GLOBAL) */ + + /* Bit 0: Reserved */ +#define LPUART_GLOBAL_RST (1 << 1) /* Bit 1: Software Reset (RST) */ + /* Bits 2-31: Reserved */ + +/* LPUART Pin Configuration Register (PINCFG) */ + +#define LPUART_PINCFG_TRGSEL_SHIFT (0) /* Bits 0-1: Trigger Select (TRGSEL) */ +#define LPUART_PINCFG_TRGSEL_MASK (0x03 << LPUART_PINCFG_TRGSEL_SHIFT) +# define LPUART_PINCFG_TRGSEL_DISABLE (0 << LPUART_PINCFG_TRGSEL_SHIFT) /* Trigger disabled */ +# define LPUART_PINCFG_TRGSEL_RXD (1 << LPUART_PINCFG_TRGSEL_SHIFT) /* Trigger used instead of RXD pin */ +# define LPUART_PINCFG_TRGSEL_CTSB (2 << LPUART_PINCFG_TRGSEL_SHIFT) /* Trigger used instead of CTS_B pin */ +# define LPUART_PINCFG_TRGSEL_TXDMOD (3 << LPUART_PINCFG_TRGSEL_SHIFT) /* Trigger used to modulate the TXD output */ + + /* Bits 2-31: Reserved */ + +/* LPUART Baud Rate Register (BAUD) */ + +#define LPUART_BAUD_SBR_SHIFT (0) /* Bits 0-12: Baud Rate Modulo Divisor (SBR) */ +#define LPUART_BAUD_SBR_MASK (0x1fff << LPUART_BAUD_SBR_SHIFT) +# define LPUART_BAUD_SBR(n) ((n) << LPUART_BAUD_SBR_SHIFT) +#define LPUART_BAUD_SBNS (1 << 13) /* Bit 13: Stop Bit Number Select (SBNS) */ +#define LPUART_BAUD_RXEDGIE (1 << 14) /* Bit 14: RX Input Active Edge Interrupt Enable (RXEDGIE) */ +#define LPUART_BAUD_LBKDIE (1 << 15) /* Bit 15: LIN Break Detect Interrupt Enable (LBKDIE) */ +#define LPUART_BAUD_RESYNCDIS (1 << 16) /* Bit 16: Resynchronization Disable (RESYNCDIS) */ +#define LPUART_BAUD_BOTHEDGE (1 << 17) /* Bit 17: Both Edge Sampling (BOTHEDGE) */ +#define LPUART_BAUD_MATCFG_SHIFT (18) /* Bits 18-19: Match Configuration (MATCFG) */ +#define LPUART_BAUD_MATCFG_MASK (0x03 << LPUART_BAUD_MATCFG_SHIFT) +# define LPUART_BAUD_MATCFG_ADDR (0 << LPUART_BAUD_MATCFG_SHIFT) /* Address Match Wakeup */ +# define LPUART_BAUD_MATCFG_IDLE (1 << LPUART_BAUD_MATCFG_SHIFT) /* Idle Match Wakeup */ +# define LPUART_BAUD_MATCFG_ONOFF (2 << LPUART_BAUD_MATCFG_SHIFT) /* Match On and Match Off */ +# define LPUART_BAUD_MATCFG_RWUENAB (3 << LPUART_BAUD_MATCFG_SHIFT) /* Enables RWU on Data Match and Match On/Off for transmitter CTS input */ + + /* Bit 20: Reserved */ +#define LPUART_BAUD_RDMAE (1 << 21) /* Bit 21: Receiver Full DMA Enable (RDMAE) */ + /* Bit 22: Reserved */ +#define LPUART_BAUD_TDMAE (1 << 23) /* Bit 23: Transmitter DMA Enable (TDMAE) */ +#define LPUART_BAUD_OSR_SHIFT (24) /* Bits 24-29: Oversampling Ratio (OSR) */ +#define LPUART_BAUD_OSR_MASK (0x1f << LPUART_BAUD_OSR_SHIFT) +# define LPUART_BAUD_OSR(n) (((n) - 1) << LPUART_BAUD_OSR_SHIFT) /* n=4..32 */ + +#define LPUART_BAUD_M10 (1 << 29) /* Bit 29: 10-bit Mode Select (M10) */ +#define LPUART_BAUD_MAEN2 (1 << 30) /* Bit 30: Match Address Mode Enable 2 (MAEN2) */ +#define LPUART_BAUD_MAEN1 (1 << 31) /* Bit 31: Match Address Mode Enable 1 (MAEN1) */ + +/* LPUART Status Register (STAT) */ + +#define LPUART_STAT_LBKFE (1 << 0) /* Bit 0: LIN Break Flag Enable (LBKFE) */ +#define LPUART_STAT_AME (1 << 1) /* Bit 1: Address Mark Enable (AME) */ + /* Bits 2-13: Reserved */ +#define LPUART_STAT_MA2F (1 << 14) /* Bit 14: Match 2 Flag (MA2F) */ +#define LPUART_STAT_MA1F (1 << 15) /* Bit 15: Match 1 Flag (MA1F) */ +#define LPUART_STAT_PF (1 << 16) /* Bit 16: Parity Error Flag (PF) */ +#define LPUART_STAT_FE (1 << 17) /* Bit 17: Framing Error Flag (FE) */ +#define LPUART_STAT_NF (1 << 18) /* Bit 18: Noise Flag (NF) */ +#define LPUART_STAT_OR (1 << 19) /* Bit 19: Receiver Overrun Flag (OR) */ +#define LPUART_STAT_IDLE (1 << 20) /* Bit 20: Idle Line Flag (IDLE) */ +#define LPUART_STAT_RDRF (1 << 21) /* Bit 21: Receive Data Register Full Flag (RDRF) */ +#define LPUART_STAT_TC (1 << 22) /* Bit 22: Transmission Complete Flag (TC) */ +#define LPUART_STAT_TDRE (1 << 23) /* Bit 23: Transmit Data Register Empty Flag (TDRE) */ +#define LPUART_STAT_RAF (1 << 24) /* Bit 24: Receiver Active Flag (RAF) */ +#define LPUART_STAT_LBKDE (1 << 25) /* Bit 25: LIN Break Detection Enable (LBKDE) */ +#define LPUART_STAT_BRK13 (1 << 26) /* Bit 26: Break Character Generation Length (BRK13) */ +#define LPUART_STAT_RWUID (1 << 27) /* Bit 27: Receive Wake Up Idle Detect (RWUID) */ +#define LPUART_STAT_RXINV (1 << 28) /* Bit 28: Receive Data Inversion (RXINV) */ +#define LPUART_STAT_MSBF (1 << 29) /* Bit 29: MSB First (MSBF) */ +#define LPUART_STAT_RXEDGIF (1 << 30) /* Bit 30: RXD Pin Active Edge Interrupt Flag (RXEDGIF) */ +#define LPUART_STAT_LBKDIF (1 << 31) /* Bit 31: LIN Break Detect Interrupt Flag (LBKDIF) */ + +/* LPUART Control Register (CTRL) */ + +#define LPUART_CTRL_PT (1 << 0) /* Bit 0: Parity Type */ +# define LPUART_CTRL_PT_EVEN (0 << 0) /* Even parity */ +# define LPUART_CTRL_PT_ODD (1 << 0) /* Odd parity */ +#define LPUART_CTRL_PE (1 << 1) /* Bit 1: Parity Enable */ +#define LPUART_CTRL_ILT (1 << 2) /* Bit 2: Idle Line Type Select */ +#define LPUART_CTRL_WAKE (1 << 3) /* Bit 3: Receiver Wakeup Method Select */ +#define LPUART_CTRL_M (1 << 4) /* Bit 4: 9-Bit or 8-Bit Mode Select */ +#define LPUART_CTRL_RSRC (1 << 5) /* Bit 5: Receiver Source Select */ +#define LPUART_CTRL_DOZEEN (1 << 6) /* Bit 6: Doze Enable */ +#define LPUART_CTRL_LOOPS (1 << 7) /* Bit 7: Loop Mode Select */ +#define LPUART_CTRL_IDLECFG_SHIFT (8) /* Bits 8-10: Idle Configuration */ +#define LPUART_CTRL_IDLECFG_MASK (0x07 << LPUART_CTRL_IDLECFG_SHIFT) +# define LPUART_CTRL_IDLECFG_1 (0 << LPUART_CTRL_IDLECFG_SHIFT) /* 1 idle character */ +# define LPUART_CTRL_IDLECFG_2 (1 << LPUART_CTRL_IDLECFG_SHIFT) /* 2 idle characters */ +# define LPUART_CTRL_IDLECFG_4 (2 << LPUART_CTRL_IDLECFG_SHIFT) /* 4 idle characters */ +# define LPUART_CTRL_IDLECFG_8 (3 << LPUART_CTRL_IDLECFG_SHIFT) /* 8 idle characters */ +# define LPUART_CTRL_IDLECFG_16 (4 << LPUART_CTRL_IDLECFG_SHIFT) /* 6 idle characters */ +# define LPUART_CTRL_IDLECFG_32 (5 << LPUART_CTRL_IDLECFG_SHIFT) /* 32 idle characters */ +# define LPUART_CTRL_IDLECFG_64 (6 << LPUART_CTRL_IDLECFG_SHIFT) /* 64 idle characters */ +# define LPUART_CTRL_IDLECFG_128 (7 << LPUART_CTRL_IDLECFG_SHIFT) /* 128 idle characters */ + +#define LPUART_CTRL_M7 (1 << 11) /* Bit 11: 7-Bit Mode Select (M7) */ + /* Bits 12-13: Reserved */ +#define LPUART_CTRL_MA2IE (1 << 14) /* Bit 14: Match 2 Interrupt Enable (MA2IE) */ +#define LPUART_CTRL_MA1IE (1 << 15) /* Bit 15: Match 1 Interrupt Enable (MA1IE) */ +#define LPUART_CTRL_SBK (1 << 16) /* Bit 16: Send Break (SBK) */ +#define LPUART_CTRL_RWU (1 << 17) /* Bit 17: Receiver Wakeup Control (RWU) */ +#define LPUART_CTRL_RE (1 << 18) /* Bit 18: Receiver Enable (RE) */ +#define LPUART_CTRL_TE (1 << 19) /* Bit 19: Transmitter Enable (TE) */ +#define LPUART_CTRL_ILIE (1 << 20) /* Bit 20: Idle Line Interrupt Enable (ILIE) */ +#define LPUART_CTRL_RIE (1 << 21) /* Bit 21: Receiver Interrupt Enable (RIE) */ +#define LPUART_CTRL_TCIE (1 << 22) /* Bit 22: Transmission Complete Interrupt Enable (TCIE) */ +#define LPUART_CTRL_TIE (1 << 23) /* Bit 23: Transmit Interrupt Enable (TIE) */ +#define LPUART_CTRL_PEIE (1 << 24) /* Bit 24: Parity Error Interrupt Enable (PEIE) */ +#define LPUART_CTRL_FEIE (1 << 25) /* Bit 25: Framing Error Interrupt Enable (FEIE) */ +#define LPUART_CTRL_NEIE (1 << 26) /* Bit 26: Noise Error Interrupt Enable (NEIE) */ +#define LPUART_CTRL_ORIE (1 << 27) /* Bit 27: Overrun Interrupt Enable (ORIE) */ +#define LPUART_CTRL_TXINV (1 << 28) /* Bit 28: Transmit Data Inversion (TXINV) */ +#define LPUART_CTRL_TXDIR (1 << 29) /* Bit 29: TXD Pin Direction in Single-Wire Mode (TXDIR) */ +#define LPUART_CTRL_R9T8 (1 << 30) /* Bit 30: Receive Bit 9 / Transmit Bit 8 (R9T8) */ +#define LPUART_CTRL_R8T9 (1 << 31) /* Bit 31: Receive Bit 8 / Transmit Bit 9 (R8T9) */ + +#define LPUART_ALL_INTS (LPUART_CTRL_ORIE | LPUART_CTRL_NEIE | LPUART_CTRL_FEIE | \ + LPUART_CTRL_PEIE | LPUART_CTRL_TIE | LPUART_CTRL_TCIE | \ + LPUART_CTRL_RIE | LPUART_CTRL_ILIE | LPUART_CTRL_MA1IE | \ + LPUART_CTRL_MA2IE) + +/* LPUART Data Register (DATA) */ + +#define LPUART_DATA_SHIFT (0) /* Bits 0-9: Data bits 0-9 (DATA)*/ +#define LPUART_DATA_MASK (0x03ff << LPUART_DATA_SHIFT) +#define LPUART_DATA_LINBRK (1 << 10) /* Bit 10: LIN Break (LINBRK) */ +#define LPUART_DATA_STATUS_SHIFT (11) /* Bits 11-15: Status */ +#define LPUART_DATA_IDLINE (1 << 11) /* Bit 11: Idle Line (IDLINE) */ +#define LPUART_DATA_RXEMPT (1 << 12) /* Bit 12: Receive Buffer Empty (RXEMPT) */ +#define LPUART_DATA_FRETSC (1 << 13) /* Bit 13: Frame Error / Transmit Special Character (FRETSC) */ +#define LPUART_DATA_PARITYE (1 << 14) /* Bit 14: Parity Error (PARITYE) */ +#define LPUART_DATA_NOISY (1 << 15) /* Bit 15: Noisy Data Received (NOISY) */ + /* Bits 16-31: Reserved */ + +/* LPUART Match Address Register (MATCH) */ + +#define LPUART_MATCH_MA1_SHIFT (0) /* Bits 0-9: Match Address 1 (MA1) */ +#define LPUART_MATCH_MA1_MASK (0x03ff << LPUART_MATCH_MA1_SHIFT) +# define LPUART_MATCH_MA1(n) ((n) << LPUART_MATCH_MA1_SHIFT) + /* Bits 10-15: Reserved */ +#define LPUART_MATCH_MA2_SHIFT (16) /* Bits 16-25: Match Address 2 (MA2) */ +#define LPUART_MATCH_MA2_MASK (0x03ff << LPUART_MATCH_MA2_SHIFT) +# define LPUART_MATCH_MA2(n) ((n) << LPUART_MATCH_MA2_SHIFT) + /* Bits 26-31: Reserved */ + +/* LPUART Modem IrDA Register (MODIR) */ + +#define LPUART_MODIR_TXCTSE (1 << 0) /* Bit 0: Transmitter clear-to-send enable (TXCTSE) */ +#define LPUART_MODIR_TXRTSE (1 << 1) /* Bit 1: Transmitter request-to-send enable (TXRTSE) */ +#define LPUART_MODIR_TXRTSPOL (1 << 2) /* Bit 2: Transmitter request-to-send polarity (TXRTSPOL) */ +#define LPUART_MODIR_RXRTSE (1 << 3) /* Bit 3: Receiver request-to-send enable (RXRTSE) */ +#define LPUART_MODIR_TXCTSC (1 << 4) /* Bit 4: Transmit CTS Configuration (TXCTSC) */ +# define LPUART_MODIR_TXCTSC_START (0 << 4) /* CTS sampled at start of character */ +# define LPUART_MODIR_TXCTSC_IDLE (1 << 4) /* CTS sampled when transmitter idle */ +#define LPUART_MODIR_TXCTSSRC (1 << 5) /* Bit 5: Transmit CTS Source (TXCTSSRC) */ +# define LPUART_MODIR_TXCTSSRC_CTSB (0 << 5) /* CTS input is CTS_B pin */ +# define LPUART_MODIR_TXCTSSRC_RXMAT (1 << 5) /* CTS input is receiver address match result */ + /* Bits 6-7: Reserved */ +#define LPUART_MODIR_RTSWATER_SHIFT (8) /* Bits 8-9: Receive RTS Configuration (RTSWATER) */ +#define LPUART_MODIR_RTSWATER_MASK (0x03 << LPUART_MODIR_RTSWATER_SHIFT) +# define LPUART_MODIR_RTSWATER(n) ((n) << LPUART_MODIR_RTSWATER_SHIFT) + /* Bits 10-15: Reserved */ +#define LPUART_MODIR_TNP_SHIFT (16) /* Bits 16-17: Transmitter narrow pulse (TNP) */ +#define LPUART_MODIR_TNP_MASK (0x03 << LPUART_MODIR_TNP_SHIFT) +# define LPUART_MODIR_TNP(n) (((n) - 1) << LPUART_MODIR_TNP_SHIFT) /* n/OSR */ + +#define LPUART_MODIR_IREN (1 << 18) /* Bit 18: Infrared enable (IREN) */ + /* Bits 19-31: Reserved */ + +/* LPUART FIFO Register (FIFO) */ + +#define LPUART_FIFO_RXFIFOSIZE_SHIFT (0) /* Bits 0-2: Receive FIFO Buffer Depth (RXFIFOSIZE) */ +#define LPUART_FIFO_RXFIFOSIZE_MASK (0x07 << LPUART_FIFO_RXFIFOSIZE_SHIFT) +# define LPUART_FIFO_RXFIFOSIZE_1 (0 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 1 dataword */ +# define LPUART_FIFO_RXFIFOSIZE_4 (1 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 4 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_8 (2 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 8 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_16 (3 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 16 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_32 (4 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 32 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_64 (5 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 64 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_128 (6 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 128 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_256 (7 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 256 datawords */ + +#define LPUART_FIFO_RXFE (1 << 3) /* Bit 3: Receive FIFO Enable (RXFE) */ +#define LPUART_FIFO_TXFIFOSIZE_SHIFT (4) /* Bits 4-6: Transmit FIFO Buffer Depth (TXFIFOSIZE) */ +#define LPUART_FIFO_TXFIFOSIZE_MASK (0x07 << LPUART_FIFO_TXFIFOSIZE_SHIFT) +# define LPUART_FIFO_TXFIFOSIZE_1 (0 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 1 dataword */ +# define LPUART_FIFO_TXFIFOSIZE_4 (1 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 4 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_8 (2 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 8 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_16 (3 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 16 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_32 (4 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 32 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_64 (5 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 64 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_128 (6 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 128 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_256 (7 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 256 datawords */ + +#define LPUART_FIFO_TXFE (1 << 7) /* Bit 7: Transmit FIFO Enable (TXFE) */ +#define LPUART_FIFO_RXUFE (1 << 8) /* Bit 8: Receive FIFO Underflow Interrupt Enable (RXUFE) */ +#define LPUART_FIFO_TXOFE (1 << 9) /* Bit 9: Transmit FIFO Overflow Interrupt Enable (TXOFE) */ +#define LPUART_FIFO_RXIDEN_SHIFT (10) /* Bits 10-12: Receiver Idle Empty Enable (RXIDEN) */ +#define LPUART_FIFO_RXIDEN_MASK (0x07 << LPUART_FIFO_RXIDEN_SHIFT) +# define LPUART_FIFO_RXIDEN_DISABLE (0 << LPUART_FIFO_RXIDEN_SHIFT) /* Disable RDRF assertion when receiver is idle */ +# define LPUART_FIFO_RXIDEN_1 (1 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 1 character */ +# define LPUART_FIFO_RXIDEN_2 (2 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 2 characters */ +# define LPUART_FIFO_RXIDEN_4 (3 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 4 characters */ +# define LPUART_FIFO_RXIDEN_8 (4 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 8 characters */ +# define LPUART_FIFO_RXIDEN_16 (5 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 16 characters */ +# define LPUART_FIFO_RXIDEN_32 (6 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 32 characters */ +# define LPUART_FIFO_RXIDEN_64 (7 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 64 characters */ + + /* Bit 13: Reserved */ +#define LPUART_FIFO_RXFLUSH (1 << 14) /* Bit 14: Receive FIFO Flush (RXFLUSH) */ +#define LPUART_FIFO_TXFLUSH (1 << 15) /* Bit 15: Transmit FIFO Flush (TXFLUSH) */ +#define LPUART_FIFO_RXUF (1 << 16) /* Bit 16: Receiver FIFO Underflow Flag (RXUF) */ +#define LPUART_FIFO_TXOF (1 << 17) /* Bit 17: Transmitter FIFO Overflow Flag (TXOF) */ + /* Bits 18-21: Reserved */ +#define LPUART_FIFO_RXEMPT (1 << 22) /* Bit 22: Receive Buffer/FIFO Empty (RXEMPT) */ +#define LPUART_FIFO_TXEMPT (1 << 23) /* Bit 23: Transmit Buffer/FIFO Empty (TXEMPT) */ + /* Bits 24-31: Reserved */ + +/* LPUART Watermark Register (WATER) */ + +#define LPUART_WATER_TXWATER_SHIFT (0) /* Bits 0-3: Transmit Watermark (TXWATER) */ +#define LPUART_WATER_TXWATER_MASK (0x0f << LPUART_WATER_TXWATER_SHIFT) +# define LPUART_WATER_TXWATER(n) ((n) << LPUART_WATER_TXWATER_SHIFT) + /* Bits 4-7: Reserved */ +#define LPUART_WATER_TXCOUNT_SHIFT (8) /* Bits 8-12: Transmit Counter (TXCOUNT) */ +#define LPUART_WATER_TXCOUNT_MASK (0x1f << LPUART_WATER_TXCOUNT_SHIFT) +# define LPUART_WATER_TXCOUNT(n) ((n) << LPUART_WATER_TXCOUNT_SHIFT) + /* Bits 13-15: Reserved */ +#define LPUART_WATER_RXWATER_SHIFT (16) /* Bits 16-19: Receive Watermark (RXWATER) */ +#define LPUART_WATER_RXWATER_MASK (0x0f << LPUART_WATER_RXWATER_SHIFT) +# define LPUART_WATER_RXWATER(n) ((n) << LPUART_WATER_RXWATER_SHIFT) + /* Bits 20-23: Reserved */ +#define LPUART_WATER_RXCOUNT_SHIFT (24) /* Bits 24-28: Receive Counter (RXCOUNT) */ +#define LPUART_WATER_RXCOUNT_MASK (0x1f << LPUART_WATER_RXCOUNT_SHIFT) +# define LPUART_WATER_RXCOUNT(n) ((n) << LPUART_WATER_RXCOUNT_SHIFT) + /* Bits 29-31: Reserved */ + +/* Data read-only Register (DATARO) */ + +#define LPUART_DATARO_DATA_SHIFT (0) /* Bits 0-15: Receive Data (DATA) */ +#define LPUART_DATARO_DATA_MASK (0xffff << LPUART_DATARO_DATA_SHIFT) + /* Bits 16-31: Reserved */ + +#endif /* __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_LPUART_H */ diff --git a/arch/arm/src/mcx-nxxx/hardware/nxxx_memorymap.h b/arch/arm/src/mcx-nxxx/hardware/nxxx_memorymap.h new file mode 100644 index 0000000000000..8af09c7b49d88 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/hardware/nxxx_memorymap.h @@ -0,0 +1,38 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/hardware/nxxx_memorymap.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_MEMORYMAP_H +#define __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_MEMORYMAP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#if defined(CONFIG_ARCH_CHIP_N236) +# include "hardware/n236/n236_memorymap.h" +#else +# error Unrecognized NXXx architecture +#endif + +#endif /* __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_MEMORYMAP_H */ diff --git a/arch/arm/src/mcx-nxxx/hardware/nxxx_port.h b/arch/arm/src/mcx-nxxx/hardware/nxxx_port.h new file mode 100644 index 0000000000000..e10c89b48cd41 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/hardware/nxxx_port.h @@ -0,0 +1,112 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/hardware/nxxx_port.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_PORT_H +#define __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_PORT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "hardware/nxxx_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NXXX_PORT1 0 +#define NXXX_PORT2 1 +#define NXXX_PORT3 2 +#define NXXX_PORT4 3 +#define NXXX_PORT5 4 +#define NXXX_PORT6 5 + +/* PORT Register Offsets ****************************************************/ +#define NXXX_PORT_GPCLR_OFFSET 0x0010 /* Global Pin Control Low Register */ +#define NXXX_PORT_GPCHR_OFFSET 0x0014 /* Global Pin Control High Register */ +#define NXXX_PORT_PCR0_OFFSET 0x0080 /* Pin Control Register 0 */ +#define NXXX_PORT_PCR_OFFSET(n) (NXXX_PORT_PCR0_OFFSET + ((n) << 2)) /* Pin Control Register n=0..31 */ + +/* PORT Register Addresses **************************************************/ + +#define NXXX_PORT_BASE(n) (NXXX_PORT0_BASE + ((n) << 12)) /* Port n multiplexing control */ +#define NXXX_PORT_PCR_BASE(p,n) (NXXX_PORT_BASE(p) + NXXX_PORT_PCR_OFFSET(n)) +#define NXXX_PORT_GPCLR(p) (NXXX_PORT_BASE(p) + NXXX_PORT_GPCLR_OFFSET) +#define NXXX_PORT_GPCHR(p) (NXXX_PORT_BASE(p) + NXXX_PORT_GPCHR_OFFSET) + +/* PORT Register Bitfield Definitions ***************************************/ + +/* Pin Control Register n=0..31 */ + +#define PORT_PCR_PS (1 << 0) /* Bit 0: Pull Select */ +# define PORT_PCR_PULLDOWN (0) /* Enable internal pulldown */ +# define PORT_PCR_PULLUP (1 << 0) /* Enable internal pullup */ +#define PORT_PCR_PE (1 << 1) /* Bit 1: Pull Enable */ +#define PORT_PCR_PV (1 << 2) /* Bit 2: Pull Value */ +#define PORT_PCR_SRE (1 << 3) /* Bit 3: Slew Rate Enable */ +#define PORT_PCR_PFE (1 << 4) /* Bit 4: Passive Filter Enable */ +#define PORT_PCR_ODE (1 << 5) /* Bit 5: Open Drain Enable */ +#define PORT_PCR_DSE (1 << 6) /* Bit 6: Drive Strength Enable */ +#define PORT_PCR_MUX_SHIFT (8) /* Bits 8-10: Pin Mux Control */ +#define PORT_PCR_MUX_MASK (15 << PORT_PCR_MUX_SHIFT) +# define PORT_PCR_MUX_GPIO (0 << PORT_PCR_MUX_SHIFT) /* Alternative 0 (GPIO) */ +# define PORT_PCR_MUX_ALT1 (1 << PORT_PCR_MUX_SHIFT) /* Alternative 1 (chip-specific) */ +# define PORT_PCR_MUX_ALT2 (2 << PORT_PCR_MUX_SHIFT) /* Alternative 2 (chip-specific) */ +# define PORT_PCR_MUX_ALT3 (3 << PORT_PCR_MUX_SHIFT) /* Alternative 3 (chip-specific) */ +# define PORT_PCR_MUX_ALT4 (4 << PORT_PCR_MUX_SHIFT) /* Alternative 4 (chip-specific) */ +# define PORT_PCR_MUX_ALT5 (5 << PORT_PCR_MUX_SHIFT) /* Alternative 5 (chip-specific) */ +# define PORT_PCR_MUX_ALT6 (6 << PORT_PCR_MUX_SHIFT) /* Alternative 6 (chip-specific) */ +# define PORT_PCR_MUX_ALT7 (7 << PORT_PCR_MUX_SHIFT) /* Alternative 7 (chip-specific) */ +# define PORT_PCR_MUX_ALT8 (8 << PORT_PCR_MUX_SHIFT) /* Alternative 8 (chip-specific) */ +# define PORT_PCR_MUX_ALT9 (9 << PORT_PCR_MUX_SHIFT) /* Alternative 9 (chip-specific) */ +# define PORT_PCR_MUX_ALT10 (10 << PORT_PCR_MUX_SHIFT) /* Alternative 10 (chip-specific) */ +# define PORT_PCR_MUX_ALT11 (11 << PORT_PCR_MUX_SHIFT) /* Alternative 11 (chip-specific) */ +# define PORT_PCR_MUX_ALT12 (12 << PORT_PCR_MUX_SHIFT) /* Alternative 12 (chip-specific) */ +# define PORT_PCR_MUX_ALT13 (13 << PORT_PCR_MUX_SHIFT) /* Alternative 13 (chip-specific) */ + +#define PORT_PCR_IBE (1 << 12) /* Bit 12: Input Buffer Enable */ +#define PORT_PCR_INV (1 << 13) /* Bit 13: Invert Input */ +#define PORT_PCR_LK (1 << 15) /* Bit 15: Lock Register */ + +/* Global Pin Control Low Register */ + +#define PORT_GPCLR_GPWD_SHIFT (0) /* Bits 0-15: Global Pin Write Data */ +#define PORT_GPCLR_GPWD_MASK (0xffff << PORT_GPCLR_GPWD_SHIFT) +# define PORT_GPCLR_GPWD_PIN(n) ((uint32_t)(n) << PORT_GPCLR_GPWD_SHIFT) /* Pin n=0..15 */ + +#define PORT_GPCLR_GPWE_SHIFT (16) /* Bits 16-31: Global Pin Write Enable */ +#define PORT_GPCLR_GPWE_MASK (0xffff << PORT_GPCLR_GPWE_SHIFT) +# define PORT_GPCLR_GPWE_PIN(n) ((uint32_t)(n) << PORT_GPCLR_GPWE_SHIFT) /* Pin n=0..15 */ + +/* Global Pin Control High Register */ + +#define PORT_GPCHR_GPWD_SHIFT (0) /* Bits 0-15: Global Pin Write Data */ +#define PORT_GPCHR_GPWD_MASK (0xffff << PORT_GPCHR_GPWD_SHIFT) +# define PORT_GPCHR_GPWD_PIN(n) ((uint32_t)((n) - 16) << PORT_GPCHR_GPWD_SHIFT) /* Pin n=16..31 */ + +#define PORT_GPCHR_GPWE_SHIFT (16) /* Bits 16-31: Global Pin Write Enable */ +#define PORT_GPCHR_GPWE_MASK (0xffff << PORT_GPCHR_GPWE_SHIFT) +# define PORT_GPCHR_GPWE_PIN(n) ((uint32_t)((n) - 16) << PORT_GPCHR_GPWE_SHIFT) /* Pin n=16..31 */ + +#endif /* __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_PORT_H */ diff --git a/arch/arm/src/mcx-nxxx/hardware/nxxx_scg.h b/arch/arm/src/mcx-nxxx/hardware/nxxx_scg.h new file mode 100644 index 0000000000000..03ac6e67b867e --- /dev/null +++ b/arch/arm/src/mcx-nxxx/hardware/nxxx_scg.h @@ -0,0 +1,535 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/hardware/nxxx_scg.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_SCG_H +#define __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_SCG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* TODO: Header file is incomplete / might contain false information */ + +/* SCG Register Offsets *****************************************************/ + +#define NXXX_SCG_VERID_OFFSET 0x0000 /* Version ID Register */ +#define NXXX_SCG_PARAM_OFFSET 0x0004 /* Parameter Register */ +#define NXXX_SCG_TRIM_LOCK_OFFSET 0x0008 /* Trim Lock Register */ +#define NXXX_SCG_CSR_OFFSET 0x0010 /* Clock Status Register */ +#define NXXX_SCG_RCCR_OFFSET 0x0014 /* Run Clock Control Register */ +#define NXXX_SCG_SOSCCSR_OFFSET 0x0100 /* System OSC Control Status Register */ +#define NXXX_SCG_SOSCDIV_OFFSET 0x0104 /* System OSC Divide Register */ +#define NXXX_SCG_SOSCCFG_OFFSET 0x0108 /* System Oscillator Configuration Register */ +#define NXXX_SCG_SIRCCSR_OFFSET 0x0200 /* Slow IRC Control Status Register */ +#define NXXX_SCG_SIRCDIV_OFFSET 0x0204 /* Slow IRC Divide Register */ +#define NXXX_SCG_SIRCCFG_OFFSET 0x0208 /* Slow IRC Configuration Register */ +#define NXXX_SCG_FIRCCSR_OFFSET 0x0300 /* Fast IRC Control Status Register */ +#define NXXX_SCG_FIRCDIV_OFFSET 0x0304 /* Fast IRC Divide Register */ +#define NXXX_SCG_FIRCCFG_OFFSET 0x0308 /* Fast IRC Configuration Register */ +#define NXXX_SCG_APLLCSR_OFFSET 0x0500 /* APLL Control Status Register */ +#define NXXX_SCG_APLLCTRL_OFFSET 0x0504 /* APLL Control Register */ +#define NXXX_SCG_APLLSTAT_OFFSET 0x0508 /* APLL Status Register */ +#define NXXX_SCG_APLLNDIV_OFFSET 0x050C /* APLL N Divider Register */ +#define NXXX_SCG_APLLMDIV_OFFSET 0x0510 /* APLL M Divider Register */ +#define NXXX_SCG_APLLPDIV_OFFSET 0x0514 /* APLL P Divider Register */ +#define NXXX_SCG_APLLLOCK_CNFG_OFFSET 0x0518 /* APLL LOCK Configuration Register */ +#define NXXX_SCG_APLLSSCGSTAT_OFFSET 0x0520 /* APLL SSCG Status Register */ +#define NXXX_SCG_APLLSSCG0_OFFSET 0x0524 /* APLL Spread Spectrum Control 0 Register */ +#define NXXX_SCG_APLLSSCG1_OFFSET 0x0528 /* APLL Spread Spectrum Control 1 Register */ +#define NXXX_SCG_APLL_OVRD_OFFSET 0x05F4 /* APLL Override Register */ +#define NXXX_SCG_SPLLCSR_OFFSET 0x0600 /* System PLL Control Status Register */ +#define NXXX_SCG_SPLLDIV_OFFSET 0x0604 /* System PLL Divide Register */ +#define NXXX_SCG_SPLLCFG_OFFSET 0x0608 /* System PLL Configuration Register */ +#define NXXX_SCG_LDOCSR_OFFSET 0x0800 /* LDO Control and Status Register */ + +/* SCG Register Addresses ***************************************************/ + +#define NXXX_SCG_VERID (NXXX_SCG0_BASE + NXXX_SCG_VERID_OFFSET) +#define NXXX_SCG_PARAM (NXXX_SCG0_BASE + NXXX_SCG_PARAM_OFFSET) +#define NXXX_SCG_TRIM_LOCK (NXXX_SCG0_BASE + NXXX_SCG_TRIM_LOCK_OFFSET) +#define NXXX_SCG_CSR (NXXX_SCG0_BASE + NXXX_SCG_CSR_OFFSET) +#define NXXX_SCG_RCCR (NXXX_SCG0_BASE + NXXX_SCG_RCCR_OFFSET) +#define NXXX_SCG_SOSCCSR (NXXX_SCG0_BASE + NXXX_SCG_SOSCCSR_OFFSET) +#define NXXX_SCG_SOSCDIV (NXXX_SCG0_BASE + NXXX_SCG_SOSCDIV_OFFSET) +#define NXXX_SCG_SOSCCFG (NXXX_SCG0_BASE + NXXX_SCG_SOSCCFG_OFFSET) +#define NXXX_SCG_SIRCCSR (NXXX_SCG0_BASE + NXXX_SCG_SIRCCSR_OFFSET) +#define NXXX_SCG_SIRCDIV (NXXX_SCG0_BASE + NXXX_SCG_SIRCDIV_OFFSET) +#define NXXX_SCG_SIRCCFG (NXXX_SCG0_BASE + NXXX_SCG_SIRCCFG_OFFSET) +#define NXXX_SCG_FIRCCSR (NXXX_SCG0_BASE + NXXX_SCG_FIRCCSR_OFFSET) +#define NXXX_SCG_FIRCDIV (NXXX_SCG0_BASE + NXXX_SCG_FIRCDIV_OFFSET) +#define NXXX_SCG_FIRCCFG (NXXX_SCG0_BASE + NXXX_SCG_FIRCCFG_OFFSET) +#define NXXX_SCG_APLLCSR (NXXX_SCG0_BASE + NXXX_SCG_APLLCSR_OFFSET) +#define NXXX_SCG_APLLCTRL (NXXX_SCG0_BASE + NXXX_SCG_APLLCTRL_OFFSET) +#define NXXX_SCG_APLLSTAT (NXXX_SCG0_BASE + NXXX_SCG_APLLSTAT_OFFSET) +#define NXXX_SCG_APLLNDIV (NXXX_SCG0_BASE + NXXX_SCG_APLLNDIV_OFFSET) +#define NXXX_SCG_APLLMDIV (NXXX_SCG0_BASE + NXXX_SCG_APLLMDIV_OFFSET) +#define NXXX_SCG_APLLPDIV (NXXX_SCG0_BASE + NXXX_SCG_APLLPDIV_OFFSET) +#define NXXX_SCG_APLLLOCK_CNFG (NXXX_SCG0_BASE + NXXX_SCG_APLLLOCK_CNFG_OFFSET) +#define NXXX_SCG_APLLSSCGSTAT (NXXX_SCG0_BASE + NXXX_SCG_APLLSSCGSTAT_OFFSET) +#define NXXX_SCG_APLLSSCG0 (NXXX_SCG0_BASE + NXXX_SCG_APLLSSCG0_OFFSET) +#define NXXX_SCG_APLLSSCG1 (NXXX_SCG0_BASE + NXXX_SCG_APLLSSCG1_OFFSET) +#define NXXX_SCG_APLL_OVRD (NXXX_SCG0_BASE + NXXX_SCG_APLL_OVRD_OFFSET) +#define NXXX_SCG_SPLLCSR (NXXX_SCG0_BASE + NXXX_SCG_SPLLCSR_OFFSET) +#define NXXX_SCG_SPLLDIV (NXXX_SCG0_BASE + NXXX_SCG_SPLLDIV_OFFSET) +#define NXXX_SCG_SPLLCFG (NXXX_SCG0_BASE + NXXX_SCG_SPLLCFG_OFFSET) +#define NXXX_CFG_LDOCSR (NXXX_SCG0_BASE + NXXX_SCG_LDOCSR_OFFSET) + +/* SCG Register Bitfield Definitions ****************************************/ + +/* Version ID Register (32-bit version number) */ + +/* Parameter Register */ + +#define SCG_PARAM_SOSC (1 << 1) /* System OSC (SOSC) clock present */ +#define SCG_PARAM_SIRC (1 << 2) /* Slow IRC (SIRC) clock present */ +#define SCG_PARAM_FIRC (1 << 3) /* Fast IRC (FIRC) clock present */ +#define SCG_PARAM_APLL (1 << 5) /* APLL (APLL) clock present */ +#define SCG_PARAM_SPLL (1 << 6) /* System PLL (SPLL) clock present */ +#define SCG_PARAM_UPLL (1 << 7) /* UPLL (UPLL) clock present */ + +/* Trim Lock Register */ + +#define SCG_TRIM_LOCK_TRIM_UNLOCK (1 << 0) /* Bit0: Locks user write access to SCG Trim and PLL LOCK */ +#define SCG_TRIM_LOCK IFR_DISABLE (1 << 1) /* Bit1: Locks IFR write access to SCG trim registers */ +#define SCG_TRIM_LOCK_TRIM_LOCK_KEY (1 << 16) /* Bits16-31: Write 5A5Ah to unlock */ + +/* Clock Status Register */ + +#define SCG_CSR_SCS_SHIFT (24) /* Bits 24-27: System clock source */ +#define SCG_CSR_SCS_MASK (15 << SCG_CSR_SCS_SHIFT) +# define SCG_CSR_SCS_SOSC (1 << SCG_CSR_SCS_SHIFT) +# define SCG_CSR_SCS_SIRC (2 << SCG_CSR_SCS_SHIFT) +# define SCG_CSR_SCS_FIRC (3 << SCG_CSR_SCS_SHIFT) +# define SCG_CSR_SCS_ROSC (4 << SCG_CSR_SCS_SHIFT) +# define SCG_CSR_SCS_APLL (5 << SCG_CSR_SCS_SHIFT) +# define SCG_CSR_SCS_SPLL (6 << SCG_CSR_SCS_SHIFT) +# define SCG_CSR_SCS_UPLL (7 << SCG_CSR_SCS_SHIFT) + +/* Run Clock Control Register */ + +#define SCG_RCCR_SCS_SHIFT (24) +#define SCG_RCCR_SCS_MASK (15 << SCG_RCCR_SCS_SHIFT) +# define SCG_RCCR_SCS_SOSC (1 << SCG_RCCR_SCS_SHIFT) /* CLK_IN */ +# define SCG_RCCR_SCS_SIRC (2 << SCG_RCCR_SCS_SHIFT) /* FRO_12MHz */ +# define SCG_RCCR_SCS_FIRC (3 << SCG_RCCR_SCS_SHIFT) /* FRO_HF */ +# define SCG_RCCR_SCS_ROSC (4 << SCG_RCCR_SCS_SHIFT) /* XTAL32K */ +# define SCG_RCCR_SCS_APLL (5 << SCG_RCCR_SCS_SHIFT) /* PLL0_CLK */ +# define SCG_RCCR_SCS_SPLL (6 << SCG_RCRR_SCS_SHIFT) /* PLL1_CLK */ +# define SCG_RCCR_SCS_UPLL (7 << SCG_RCCR_SCS_SHIFT) /* USB_PLL_CLK */ + +/* System OSC Control Status Register */ + +#define SCG_SOSCCSR_SOSCEN (1 << 0) /* Bit 0: System OSC Enable */ +#define SCG_SOSCCSR_SOSCCM (1 << 16) /* Bit 16: System OSC Clock Monitor */ +#define SCG_SOSCCSR_SOSCCMRE (1 << 17) /* Bit 17: System OSC Clock Monitor Reset Enable */ +#define SCG_SOSCCSR_LK (1 << 23) /* Bit 23: Lock Register */ +#define SCG_SOSCCSR_SOSCVLD (1 << 24) /* Bit 24: System OSC Valid */ +#define SCG_SOSCCSR_SOSCSEL (1 << 25) /* Bit 25: System OSC Selected */ +#define SCG_SOSCCSR_SOSCERR (1 << 26) /* Bit 26: System OSC Clock Error */ + +/* System OSC Divide Register */ + +#define SCG_SOSCDIV_SOSCDIV1_SHIFT (0) /* Bits 0-2: System OSC Clock Divide 1 */ +#define SCG_SOSCDIV_SOSCDIV1_MASK (7 << SCG_SOSCDIV_SOSCDIV1_SHIFT) +# define SCG_SOSCDIV_SOSCDIV1(n) ((uint32_t)(n) << SCG_SOSCDIV_SOSCDIV1_SHIFT) +# define SCG_SOSCDIV_SOSCDIV1_DISABLE (0 << SCG_SOSCDIV_SOSCDIV1_SHIFT) /* Output disabled */ +# define SCG_SOSCDIV_SOSCDIV1_DIV1 (1 << SCG_SOSCDIV_SOSCDIV1_SHIFT) /* Divide by 1 */ +# define SCG_SOSCDIV_SOSCDIV1_DIV2 (2 << SCG_SOSCDIV_SOSCDIV1_SHIFT) /* Divide by 2 */ +# define SCG_SOSCDIV_SOSCDIV1_DIV4 (3 << SCG_SOSCDIV_SOSCDIV1_SHIFT) /* Divide by 4 */ +# define SCG_SOSCDIV_SOSCDIV1_DIV8 (4 << SCG_SOSCDIV_SOSCDIV1_SHIFT) /* Divide by 8 */ +# define SCG_SOSCDIV_SOSCDIV1_DIV16 (5 << SCG_SOSCDIV_SOSCDIV1_SHIFT) /* Divide by 16 */ +# define SCG_SOSCDIV_SOSCDIV1_DIV32 (6 << SCG_SOSCDIV_SOSCDIV1_SHIFT) /* Divide by 32 */ +# define SCG_SOSCDIV_SOSCDIV1_DIV64 (7 << SCG_SOSCDIV_SOSCDIV1_SHIFT) /* Divide by 64 */ + +#define SCG_SOSCDIV_SOSCDIV2_SHIFT (8) /* Bits 8-10: System OSC Clock Divide 2 */ +#define SCG_SOSCDIV_SOSCDIV2_MASK (7 << SCG_SOSCDIV_SOSCDIV2_SHIFT) +# define SCG_SOSCDIV_SOSCDIV2(n) ((uint32_t)(n) << SCG_SOSCDIV_SOSCDIV2_SHIFT) +# define SCG_SOSCDIV_SOSCDIV2_DISABLE (0 << SCG_SOSCDIV_SOSCDIV2_SHIFT) /* Output disabled */ +# define SCG_SOSCDIV_SOSCDIV2_DIV1 (1 << SCG_SOSCDIV_SOSCDIV2_SHIFT) /* Divide by 1 */ +# define SCG_SOSCDIV_SOSCDIV2_DIV2 (2 << SCG_SOSCDIV_SOSCDIV2_SHIFT) /* Divide by 2 */ +# define SCG_SOSCDIV_SOSCDIV2_DIV4 (3 << SCG_SOSCDIV_SOSCDIV2_SHIFT) /* Divide by 4 */ +# define SCG_SOSCDIV_SOSCDIV2_DIV8 (4 << SCG_SOSCDIV_SOSCDIV2_SHIFT) /* Divide by 8 */ +# define SCG_SOSCDIV_SOSCDIV2_DIV16 (5 << SCG_SOSCDIV_SOSCDIV2_SHIFT) /* Divide by 16 */ +# define SCG_SOSCDIV_SOSCDIV2_DIV32 (6 << SCG_SOSCDIV_SOSCDIV2_SHIFT) /* Divide by 32 */ +# define SCG_SOSCDIV_SOSCDIV2_DIV64 (7 << SCG_SOSCDIV_SOSCDIV2_SHIFT) /* Divide by 64 */ + +/* System Oscillator Configuration Register */ + +#define SCG_SOSCCFG_EREFS (1 << 2) /* Bit 2: External Reference Select */ +#define SCG_SOSCCFG_HGO (1 << 3) /* Bit 3: High Gain Oscillator Select */ +#define SCG_SOSCCFG_RANGE_SHIFT (4) /* Bits 4-5: System OSC Range Select */ +#define SCG_SOSCCFG_RANGE_MASK (3 << SCG_SOSCCFG_RANGE_SHIFT) +# define SCG_SOSCCFG_RANGE(n) ((uint32_t)(n) << SCG_SOSCCFG_RANGE_SHIFT) +# define SCG_SOSCCFG_RANGE_LOW (1 << SCG_SOSCCFG_RANGE_SHIFT) /* Low frequency range */ +# define SCG_SOSCCFG_RANGE_MED (2 << SCG_SOSCCFG_RANGE_SHIFT) /* Medium frequency range */ +# define SCG_SOSCCFG_RANGE_HIGH (3 << SCG_SOSCCFG_RANGE_SHIFT) /* High frequency range */ + +/* Slow IRC Control Status Register */ + +#define SCG_SIRCCSR_SIRCEN (1 << 0) /* Bit 0: Slow IRC Enable */ +#define SCG_SIRCCSR_SIRCSTEN (1 << 1) /* Bit 1: Slow IRC Stop Enable */ +#define SCG_SIRCCSR_SIRCLPEN (1 << 2) /* Bit 2: Slow IRC Low Power Enable */ +#define SCG_SIRCCSR_LK (1 << 23) /* Bit 23: Lock Register */ +#define SCG_SIRCCSR_SIRCVLD (1 << 24) /* Bit 24: Slow IRC Valid */ +#define SCG_SIRCCSR_SIRCSEL (1 << 25) /* Bit 25: Slow IRC Selected */ + +/* Slow IRC Divide Register */ + +#define SCG_SIRCDIV_SIRCDIV1_SHIFT (0) /* Bits 0-2: Slow IRC Clock Divide 1 */ +#define SCG_SIRCDIV_SIRCDIV1_MASK (7 << SCG_SIRCDIV_SIRCDIV1_SHIFT) +# define SCG_SIRCDIV_SIRCDIV1(n) ((uint32_t)(n) << SCG_SIRCDIV_SIRCDIV1_SHIFT) +# define SCG_SIRCDIV_SIRCDIV1_DISABLE (0 << SCG_SIRCDIV_SIRCDIV1_SHIFT) /* Output disabled */ +# define SCG_SIRCDIV_SIRCDIV1_DIV1 (1 << SCG_SIRCDIV_SIRCDIV1_SHIFT) /* Divide by 1 */ +# define SCG_SIRCDIV_SIRCDIV1_DIV2 (2 << SCG_SIRCDIV_SIRCDIV1_SHIFT) /* Divide by 2 */ +# define SCG_SIRCDIV_SIRCDIV1_DIV4 (3 << SCG_SIRCDIV_SIRCDIV1_SHIFT) /* Divide by 4 */ +# define SCG_SIRCDIV_SIRCDIV1_DIV8 (4 << SCG_SIRCDIV_SIRCDIV1_SHIFT) /* Divide by 8 */ +# define SCG_SIRCDIV_SIRCDIV1_DIV16 (5 << SCG_SIRCDIV_SIRCDIV1_SHIFT) /* Divide by 16 */ +# define SCG_SIRCDIV_SIRCDIV1_DIV32 (6 << SCG_SIRCDIV_SIRCDIV1_SHIFT) /* Divide by 32 */ +# define SCG_SIRCDIV_SIRCDIV1_DIV64 (7 << SCG_SIRCDIV_SIRCDIV1_SHIFT) /* Divide by 64 */ + +#define SCG_SIRCDIV_SIRCDIV2_SHIFT (8) /* Bits 8-10: Slow IRC Clock Divide 2 */ +#define SCG_SIRCDIV_SIRCDIV2_MASK (7 << SCG_SIRCDIV_SIRCDIV2_SHIFT) +# define SCG_SIRCDIV_SIRCDIV2(n) ((uint32_t)(n) << SCG_SIRCDIV_SIRCDIV2_SHIFT) +# define SCG_SIRCDIV_SIRCDIV2_DISABLE (0 << SCG_SIRCDIV_SIRCDIV2_SHIFT) /* Output disabled */ +# define SCG_SIRCDIV_SIRCDIV2_DIV1 (1 << SCG_SIRCDIV_SIRCDIV2_SHIFT) /* Divide by 1 */ +# define SCG_SIRCDIV_SIRCDIV2_DIV2 (2 << SCG_SIRCDIV_SIRCDIV2_SHIFT) /* Divide by 2 */ +# define SCG_SIRCDIV_SIRCDIV2_DIV4 (3 << SCG_SIRCDIV_SIRCDIV2_SHIFT) /* Divide by 4 */ +# define SCG_SIRCDIV_SIRCDIV2_DIV8 (4 << SCG_SIRCDIV_SIRCDIV2_SHIFT) /* Divide by 8 */ +# define SCG_SIRCDIV_SIRCDIV2_DIV16 (5 << SCG_SIRCDIV_SIRCDIV2_SHIFT) /* Divide by 16 */ +# define SCG_SIRCDIV_SIRCDIV2_DIV32 (6 << SCG_SIRCDIV_SIRCDIV2_SHIFT) /* Divide by 32 */ +# define SCG_SIRCDIV_SIRCDIV2_DIV64 (7 << SCG_SIRCDIV_SIRCDIV2_SHIFT) /* Divide by 64 */ + +/* Slow IRC Configuration Register */ + +#define SCG_SIRCCFG_RANGE (1 << 0) /* Bit 0: Frequency Range */ +# define SCG_SIRCCFG_LOWRANGE (0) /* Slow IRC low range clock (2 MHz) */ +# define SCG_SIRCCFG_HIGHRANGE (1 << 0) /* Slow IRC high range clock (8 MHz ) */ + +/* Fast IRC Control Status Register */ + +#define SCG_FIRCCSR_FIRCEN (1 << 0) /* Bit 0: Fast IRC Enable */ +#define SCG_FIRCCSR_FIRCSTEN (1 << 1) /* Bit 1: Stop enable */ +#define SCG_FIRCCSR_SCLK_PERIPH_EN (1 << 4) /* Bit 2: Fast IRC 48 MHz Clock to peripherals Enable */ +#define SCG_FIRCCSR_FCLK_PERIPH_EN (1 << 5) /* Bit 3: Fast IRC 144 MHz clock to peripherals Enable */ +#define SCG_FIRCCSR_FIRCTREN (1 << 8) /* Bit 8: Fast IRC 144 MHz Trim Enable */ +#define SCG_FIRCCSR_FIRCTRUP (1 << 9) /* Bit 9: Fast IRC Trim Update */ +#define SCG_FIRCCSR_TRIM_LOCK (1 << 10) /* Bit 10: Fast IRC auto trim lock */ +#define SCG_FIRCCSR_COARSE_TRIM_BYPASS (1 << 11) /* Bit 11: Coarse Auto Trim Bypass */ +#define SCG_FIRCCSR_LK (1 << 23) /* Bit 23: Lock Register */ +#define SCG_FIRCCSR_FIRCVLD (1 << 24) /* Bit 24: Fast IRC Valid status */ +#define SCG_FIRCCSR_FIRCSEL (1 << 25) /* Bit 25: Fast IRC Selected status */ +#define SCG_FIRCCSR_FIRCERR (1 << 26) /* Bit 26: Fast IRC Clock Error */ +#define SCG_FIRCCSR_FIRCERR_IE (1 << 27) /* Bit 26: Fast IRC Clock Error Interrupt Enable */ +#define SCG_FIRCCSR_FIRCACC_IE (1 << 30) /* Bit 30: Fast IRC Accurate Interrupt Enable */ +#define SCG_FIRCCSR_FIRCACC (1 << 31) /* Bit 30: Fast IRC Frequency Accurate */ + +/* Fast IRC Divide Register */ + +#define SCG_FIRCDIV_FIRCDIV1_SHIFT (0) /* Bits 0-2: Fast IRC Clock Divide 1 */ +#define SCG_FIRCDIV_FIRCDIV1_MASK (7 << SCG_FIRCDIV_FIRCDIV1_SHIFT) +# define SCG_FIRCDIV_FIRCDIV1(n) ((uint32_t)(n) << SCG_FIRCDIV_FIRCDIV1_SHIFT) +# define SCG_FIRCDIV_FIRCDIV1_DISABLE (0 << SCG_FIRCDIV_FIRCDIV1_SHIFT) /* Output disabled */ +# define SCG_FIRCDIV_FIRCDIV1_DIV1 (1 << SCG_FIRCDIV_FIRCDIV1_SHIFT) /* Divide by 1 */ +# define SCG_FIRCDIV_FIRCDIV1_DIV2 (2 << SCG_FIRCDIV_FIRCDIV1_SHIFT) /* Divide by 2 */ +# define SCG_FIRCDIV_FIRCDIV1_DIV4 (3 << SCG_FIRCDIV_FIRCDIV1_SHIFT) /* Divide by 4 */ +# define SCG_FIRCDIV_FIRCDIV1_DIV8 (4 << SCG_FIRCDIV_FIRCDIV1_SHIFT) /* Divide by 8 */ +# define SCG_FIRCDIV_FIRCDIV1_DIV16 (5 << SCG_FIRCDIV_FIRCDIV1_SHIFT) /* Divide by 16 */ +# define SCG_FIRCDIV_FIRCDIV1_DIV32 (6 << SCG_FIRCDIV_FIRCDIV1_SHIFT) /* Divide by 32 */ +# define SCG_FIRCDIV_FIRCDIV1_DIV64 (7 << SCG_FIRCDIV_FIRCDIV1_SHIFT) /* Divide by 64 */ + +#define SCG_FIRCDIV_FIRCDIV2_SHIFT (8) /* Bits 8-10: Fast IRC Clock Divide 2 */ +#define SCG_FIRCDIV_FIRCDIV2_MASK (7 << SCG_FIRCDIV_FIRCDIV2_SHIFT) +# define SCG_FIRCDIV_FIRCDIV2(n) ((uint32_t)(n) << SCG_FIRCDIV_FIRCDIV2_SHIFT) +# define SCG_FIRCDIV_FIRCDIV2_DISABLE (0 << SCG_FIRCDIV_FIRCDIV2_SHIFT) /* Output disabled */ +# define SCG_FIRCDIV_FIRCDIV2_DIV1 (1 << SCG_FIRCDIV_FIRCDIV2_SHIFT) /* Divide by 1 */ +# define SCG_FIRCDIV_FIRCDIV2_DIV2 (2 << SCG_FIRCDIV_FIRCDIV2_SHIFT) /* Divide by 2 */ +# define SCG_FIRCDIV_FIRCDIV2_DIV4 (3 << SCG_FIRCDIV_FIRCDIV2_SHIFT) /* Divide by 4 */ +# define SCG_FIRCDIV_FIRCDIV2_DIV8 (4 << SCG_FIRCDIV_FIRCDIV2_SHIFT) /* Divide by 8 */ +# define SCG_FIRCDIV_FIRCDIV2_DIV16 (5 << SCG_FIRCDIV_FIRCDIV2_SHIFT) /* Divide by 16 */ +# define SCG_FIRCDIV_FIRCDIV2_DIV32 (6 << SCG_FIRCDIV_FIRCDIV2_SHIFT) /* Divide by 32 */ +# define SCG_FIRCDIV_FIRCDIV2_DIV64 (7 << SCG_FIRCDIV_FIRCDIV2_SHIFT) /* Divide by 64 */ + +/* Fast IRC Configuration Register */ + +#define SCG_FIRCCFG_RANGE (1 << 0) /* Bit 0: Frequency Range */ +# define SCG_FIRCCFG_48MHZ (0) /* Fast IRC is trimmed to 48 MHz */ + +/* APLL Control Status Register */ + +#define SCG_APLLCSR_APLLPWREN_SHIFT (0) +#define SCG_APLLCSR_APLLPWREN_MASK (0x01 << SCG_APLLCSR_APLLPWREN_SHIFT) +#define SCG_APLLCSR_APLLPWREN(x) (((x) << SCG_APLLCSR_APLLPWREN_SHIFT) & SCG_APLLCSR_APLLPWREN_MASK) + +#define SCG_APLLCSR_APLLCLKEN_SHIFT (1) +#define SCG_APLLCSR_APLLCLKEN_MASK (0x01 << SCG_APLLCSR_APLLCLKEN_SHIFT) +#define SCG_APLLCSR_APLLCLKEN(x) (((x) << SCG_APLLCSR_APLLCLKEN_SHIFT) & SCG_APLLCSR_APLLCLKEN_MASK) + +#define SCG_APLLCSR_APLLSTEN_SHIFT (2) +#define SCG_APLLCSR_APLLSTEN_MASK (0x01 << SCG_APLLCSR_APLLSTEN_SHIFT) +#define SCG_APLLCSR_APLLSTEN(x) (((x) << SCG_APLLCSR_APLLSTEN_SHIFT) & SCG_APLLCSR_APLLSTEN_MASK) + +#define SCG_APLLCSR_FRM_CLOCKSTABLE_SHIFT (3) +#define SCG_APLLCSR_FRM_CLOCKSTABLE_MASK (0x01 << SCG_APLLCSR_FRM_CLOCKSTABLE_SHIFT) +#define SCG_APLLCSR_FRM_CLOCKSTABLE(x) (((x) << SCG_APLLCSR_FRM_CLOCKSTABLE_SHIFT) & SCG_APLLCSR_FRM_CLOCKSTABLE_MASK) + +#define SCG_APLLCSR_APLLCM_SHIFT (16) +#define SCG_APLLCSR_APLLCM_MASK (0x01 << SCG_APLLCSR_APLLCM_SHIFT) +#define SCG_APLLCSR_APLLCM(x) (((x) << SCG_APLLCSR_APLLCM_SHIFT) & SCG_APLLCSR_APLLCM_MASK) + +#define SCG_APLLCSR_APLLCMRE_SHIFT (17) +#define SCG_APLLCSR_APLLCMRE_MASK (0x01 << SCG_APLLCSR_APLLCMRE_SHIFT) +#define SCG_APLLCSR_APLLCMRE(x) (((x) << SCG_APLLCSR_APLLCMRE_SHIFT) & SCG_APLLCSR_APLLCMRE_MASK) + +#define SCG_APLLCSR_LK_SHIFT (23) +#define SCG_APLLCSR_LK_MASK (0x01 << SCG_APLLCSR_LK_SHIFT) +#define SCG_APLLCSR_LK(x) (((x) << SCG_APLLCSR_LK_SHIFT) & SCG_APLLCSR_LK_MASK) + +#define SCG_APLLCSR_APLL_LOCK_SHIFT (24) +#define SCG_APLLCSR_APLL_LOCK_MASK (0x01 << SCG_APLLCSR_APLL_LOCK_SHIFT) +#define SCG_APLLCSR_APLL_LOCK(x) (((x) << SCG_APLLCSR_APLL_LOCK_SHIFT) & SCG_APLLCSR_APLL_LOCK_MASK) + +#define SCG_APLLCSR_APLLSEL_SHIFT (25) +#define SCG_APLLCSR_APLLSEL_MASK (0x01 << SCG_APLLCSR_APLLSEL_SHIFT) +#define SCG_APLLCSR_APLLSEL(x) (((x) << SCG_APLLCSR_APLLSEL_SHIFT) & SCG_APLLCSR_APLLSEL_MASK) + +#define SCG_APLLCSR_APLLERR_SHIFT (26) +#define SCG_APLLCSR_APLLERR_MASK (0x01 << SCG_APLLCSR_APLLERR_SHIFT) +#define SCG_APLLCSR_APLLERR(x) (((x) << SCG_APLLCSR_APLLERR_SHIFT) & SCG_APLLCSR_APLLERR_MASK) + +#define SCG_APLLCSR_APLL_LOCK_IE_SHIFT (30) +#define SCG_APLLCSR_APLL_LOCK_IE_MASK (0x01 << SCG_APLLCSR_APLL_LOCK_IE_SHIFT) +#define SCG_APLLCSR_APLL_LOCK_IE(x) (((x) << SCG_APLLCSR_APLL_LOCK_IE_SHIFT) & SCG_APLLCSR_APLL_LOCK_IE_MASK) + +/* APLL Control Register */ + +#define SCG_APLLCTRL_SELR_SHIFT (0) +#define SCG_APLLCTRL_SELR_MASK (0x0f << SCG_APLLCTRL_SELR_SHIFT) +#define SCG_APLLCTRL_SELR(x) (((x) << SCG_APLLCTRL_SELR_SHIFT) & SCG_APLLCTRL_SELR_MASK) + +#define SCG_APLLCTRL_SELI_SHIFT (4) +#define SCG_APLLCTRL_SELI_MASK (0x3f << SCG_APLLCTRL_SELI_SHIFT) +#define SCG_APLLCTRL_SELI(x) (((x) << SCG_APLLCTRL_SELI_SHIFT) & SCG_APLLCTRL_SELI_MASK) + +#define SCG_APLLCTRL_SELP_SHIFT (10) +#define SCG_APLLCTRL_SELP_MASK (0x1f << SCG_APLLCTRL_SELP_SHIFT) +#define SCG_APLLCTRL_SELP(x) (((x) << SCG_APLLCTRL_SELP_SHIFT) & SCG_APLLCTRL_SELP_MASK) + +#define SCG_APLLCTRL_BYPASSPOSTDIV2_SHIFT (16) +#define SCG_APLLCTRL_BYPASSPOSTDIV2_MASK (0x01 << SCG_APLLCTRL_BYPASSPOSTDIV2_SHIFT) +#define SCG_APLLCTRL_BYPASSPOSTDIV2(x) (((x) << SCG_APLLCTRL_BYPASSPOSTDIV2_SHIFT) & SCG_APLLCTRL_BYPASSPOSTDIV2_MASK) + +#define SCG_APLLCTRL_LIMUPOFF_SHIFT (17) +#define SCG_APLLCTRL_LIMUPOFF_MASK (0x01 << SCG_APLLCTRL_LIMUPOFF_SHIFT) +#define SCG_APLLCTRL_LIMUPOFF(x) (((x) << SCG_APLLCTRL_LIMUPOFF_SHIFT) & SCG_APLLCTRL_LIMUPOFF_MASK) + +#define SCG_APLLCTRL_BANDDIRECT_SHIFT (18) +#define SCG_APLLCTRL_BANDDIRECT_MASK (0x01 << SCG_APLLCTRL_BANDDIRECT_SHIFT) +#define SCG_APLLCTRL_BANDDIRECT(x) (((x) << SCG_APLLCTRL_BANDDIRECT_SHIFT) & SCG_APLLCTRL_BANDDIRECT_MASK) + +#define SCG_APLLCTRL_BYPASSPREDIV_SHIFT (19) +#define SCG_APLLCTRL_BYPASSPREDIV_MASK (0x01 << SCG_APLLCTRL_BYPASSPREDIV_SHIFT) +#define SCG_APLLCTRL_BYPASSPREDIV(x) (((x) << SCG_APLLCTRL_BYPASSPREDIV_SHIFT) & SCG_APLLCTRL_BYPASSPREDIV_MASK) + +#define SCG_APLLCTRL_BYPASSPOSTDIV_SHIFT (20) +#define SCG_APLLCTRL_BYPASSPOSTDIV_MASK (0x01 << SCG_APLLCTRL_BYPASSPOSTDIV_SHIFT) +#define SCG_APLLCTRL_BYPASSPOSTDIV(x) (((x) << SCG_APLLCTRL_BYPASSPOSTDIV_SHIFT) & SCG_APLLCTRL_BYPASSPOSTDIV_MASK) + +#define SCG_APLLCTRL_FRM_SHIFT (22) +#define SCG_APLLCTRL_FRM_MASK (0x01 << SCG_APLLCTRL_FRM_SHIFT) +#define SCG_APLLCTRL_FRM(x) (((x) << SCG_APLLCTRL_FRM_SHIFT) & SCG_APLLCTRL_FRM_MASK) + +#define SCG_APLLCTRL_SOURCE_SHIFT (25) +#define SCG_APLLCTRL_SOURCE_MASK (0x01 << SCG_APLLCTRL_SOURCE_SHIFT) +#define SCG_APLLCTRL_SOURCE(x) (((x) << SCG_APLLCTRL_SOURCE_SHIFT) & SCG_APLLCTRL_SOURCE_MASK) + +/* APLL Status Register */ + +#define SCG_APLLSTAT_NDIVACK_SHIFT (1) +#define SCG_APLLSTAT_NDIVACK_MASK (0x01 << SCG_APLLSTAT_NDIVACK_SHIFT) +#define SCG_APLLSTAT_NDIVACK(x) (((x) << SCG_APLLSTAT_NDIVACK_SHIFT) & SCG_APLLSTAT_NDIVACK_MASK) + +#define SCG_APLLSTAT_MDIVACK_SHIFT (2) +#define SCG_APLLSTAT_MDIVACK_MASK (0x01 << SCG_APLLSTAT_MDIVACK_SHIFT) +#define SCG_APLLSTAT_MDIVACK(x) (((x) << SCG_APLLSTAT_MDIVACK_SHIFT) & SCG_APLLSTAT_MDIVACK_MASK) + +#define SCG_APLLSTAT_PDIVACK_SHIFT (3) +#define SCG_APLLSTAT_PDIVACK_MASK (0x01 << SCG_APLLSTAT_PDIVACK_SHIFT) +#define SCG_APLLSTAT_PDIVACK(x) (((x) << SCG_APLLSTAT_PDIVACK_SHIFT) & SCG_APLLSTAT_PDIVACK_MASK) + +#define SCG_APLLSTAT_FRMDET_SHIFT (4) +#define SCG_APLLSTAT_FRMDET_MASK (0x01 << SCG_APLLSTAT_FRMDET_SHIFT) +#define SCG_APLLSTAT_FRMDET(x) (((x) << SCG_APLLSTAT_FRMDET_SHIFT) & SCG_APLLSTAT_FRMDET_MASK) + +/* APLL N Divider Register */ + +#define SCG_APLLNDIV_NDIV_SHIFT (0) +#define SCG_APLLNDIV_NDIV_MASK (0xff << SCG_APLLNDIV_NDIV_SHIFT) +#define SCG_APLLNDIV_NDIV(x) (((x) << SCG_APLLNDIV_NDIV_SHIFT) & SCG_APLLNDIV_NDIV_MASK) + +#define SCG_APLLNDIV_NREQ_SHIFT (31) +#define SCG_APLLNDIV_NREQ_MASK (0x01 << SCG_APLLNDIV_NREQ_SHIFT) +#define SCG_APLLNDIV_NREQ(x) (((x) << SCG_APLLNDIV_NREQ_SHIFT) & SCG_APLLNDIV_NREQ_MASK) + +/* APLL M Divider Register */ + +#define SCG_APLLMDIV_MDIV_SHIFT (0) +#define SCG_APLLMDIV_MDIV_MASK (0xffff << SCG_APLLMDIV_MDIV_SHIFT) +#define SCG_APLLMDIV_MDIV(x) (((x) << SCG_APLLMDIV_MDIV_SHIFT) & SCG_APLLMDIV_MDIV_MASK) + +#define SCG_APLLMDIV_MREQ_SHIFT (31) +#define SCG_APLLMDIV_MREQ_MASK (0x01 << SCG_APLLMDIV_MREQ_SHIFT) +#define SCG_APLLMDIV_MREQ(x) (((x) << SCG_APLLMDIV_MREQ_SHIFT) & SCG_APLLMDIV_MREQ_MASK) + +/* APLL P Divider Register */ + +#define SCG_APLLPDIV_PDIV_SHIFT (0) +#define SCG_APLLPDIV_PDIV_MASK (0x1f << SCG_APLLPDIV_PDIV_SHIFT) +#define SCG_APLLPDIV_PDIV(x) (((x) << SCG_APLLPDIV_PDIV_SHIFT) & SCG_APLLPDIV_PDIV_MASK) + +#define SCG_APLLPDIV_PREQ_SHIFT (31) +#define SCG_APLLPDIV_PREQ_MASK (0x01 << SCG_APLLPDIV_PREQ_SHIFT) +#define SCG_APLLPDIV_PREQ(x) (((x) << SCG_APLLPDIV_PREQ_SHIFT) & SCG_APLLPDIV_PREQ_MASK) + +/* APLL LOCK Configuration Register */ + +#define SCG_APLLLOCK_CNFG_LOCK_TIME_SHIFT (0) +#define SCG_APLLLOCK_CNFG_LOCK_TIME_MASK (0x1ffff << SCG_APLLLOCK_CNFG_LOCK_TIME_SHIFT) +#define SCG_APLLLOCK_CNFG_LOCK_TIME(x) (((x) << SCG_APLLLOCK_CNFG_LOCK_TIME_SHIFT) & SCG_APLLLOCK_CNFG_LOCK_TIME_MASK) + +/* APLL SSCG Status Register */ + +#define SCG_APLLSSCGSTAT_SS_MDIV_ACK_SHIFT (0) +#define SCG_APLLSSCGSTAT_SS_MDIV_ACK_MASK (0x01 << SCG_APLLSSCGSTAT_SS_MDIV_ACK_SHIFT) +#define SCG_APLLSSCGSTAT_SS_MDIV_ACK(x) (((x) << SCG_APLLSSCGSTAT_SS_MDIV_ACK_SHIFT) & SCG_APLLSSCGSTAT_SS_MDIV_ACK_MASK) + +/* APLL Spread Spectrum Control 0 Register */ + +#define SCG_APLLSSCG0_SS_MDIV_LSB_SHIFT (0) +#define SCG_APLLSSCG0_SS_MDIV_LSB_MASK (0xffffffff << SCG_APLLSSCG0_SS_MDIV_LSB_SHIFT) +#define SCG_APLLSSCG0_SS_MDIV_LSB(x) (((x) << SCG_APLLSSCG0_SS_MDIV_LSB_SHIFT) & SCG_APLLSSCG0_SS_MDIV_LSB_MASK) + +/* APLL Spread Spectrum Control 1 Register */ + +#define SCG_APLLSSCG1_SS_MDIV_MSB_SHIFT (0) +#define SCG_APLLSSCG1_SS_MDIV_MSB_MASK (0x01 << SCG_APLLSSCG1_SS_MDIV_MSB_SHIFT) +#define SCG_APLLSSCG1_SS_MDIV_MSB(x) (((x) << SCG_APLLSSCG1_SS_MDIV_MSB_SHIFT) & SCG_APLLSSCG1_SS_MDIV_MSB_MASK) + +#define SCG_APLLSSCG1_SS_MDIV_REQ_SHIFT (1) +#define SCG_APLLSSCG1_SS_MDIV_REQ_MASK (0x01 << SCG_APLLSSCG1_SS_MDIV_REQ_SHIFT) +#define SCG_APLLSSCG1_SS_MDIV_REQ(x) (((x) << SCG_APLLSSCG1_SS_MDIV_REQ_SHIFT) & SCG_APLLSSCG1_SS_MDIV_REQ_MASK) + +#define SCG_APLLSSCG1_MF_SHIFT (2) +#define SCG_APLLSSCG1_MF_MASK (0x07 << SCG_APLLSSCG1_MF_SHIFT) +#define SCG_APLLSSCG1_MF(x) (((x) << SCG_APLLSSCG1_MF_SHIFT) & SCG_APLLSSCG1_MF_MASK) + +#define SCG_APLLSSCG1_MR_SHIFT (5) +#define SCG_APLLSSCG1_MR_MASK (0x07 << SCG_APLLSSCG1_MR_SHIFT) +#define SCG_APLLSSCG1_MR(x) (((x) << SCG_APLLSSCG1_MR_SHIFT) & SCG_APLLSSCG1_MR_MASK) + +#define SCG_APLLSSCG1_MC_SHIFT (8) +#define SCG_APLLSSCG1_MC_MASK (0x03 << SCG_APLLSSCG1_MC_SHIFT) +#define SCG_APLLSSCG1_MC(x) (((x) << SCG_APLLSSCG1_MC_SHIFT) & SCG_APLLSSCG1_MC_MASK) + +#define SCG_APLLSSCG1_DITHER_SHIFT (10) +#define SCG_APLLSSCG1_DITHER_MASK (0x01 << SCG_APLLSSCG1_DITHER_SHIFT) +#define SCG_APLLSSCG1_DITHER(x) (((x) << SCG_APLLSSCG1_DITHER_SHIFT) & SCG_APLLSSCG1_DITHER_MASK) + +#define SCG_APLLSSCG1_SEL_SS_MDIV_SHIFT (11) +#define SCG_APLLSSCG1_SEL_SS_MDIV_MASK (0x01 << SCG_APLLSSCG1_SEL_SS_MDIV_SHIFT) +#define SCG_APLLSSCG1_SEL_SS_MDIV(x) (((x) << SCG_APLLSSCG1_SEL_SS_MDIV_SHIFT) & SCG_APLLSSCG1_SEL_SS_MDIV_MASK) + +#define SCG_APLLSSCG1_SS_PD_SHIFT (31) +#define SCG_APLLSSCG1_SS_PD_MASK (0x01 << SCG_APLLSSCG1_SS_PD_SHIFT) +#define SCG_APLLSSCG1_SS_PD(x) (((x) << SCG_APLLSSCG1_SS_PD_SHIFT) & SCG_APLLSSCG1_SS_PD_MASK) + +/* APLL Override Register */ + +#define SCG_APLL_OVRD_APLLPWREN_OVRD_SHIFT (0) +#define SCG_APLL_OVRD_APLLPWREN_OVRD_MASK (0x01 << SCG_APLL_OVRD_APLLPWREN_OVRD_SHIFT) +#define SCG_APLL_OVRD_APLLPWREN_OVRD(x) (((x) << SCG_APLL_OVRD_APLLPWREN_OVRD_SHIFT) & SCG_APLL_OVRD_APLLPWREN_OVRD_MASK) + +#define SCG_APLL_OVRD_APLLCLKEN_OVRD_SHIFT (1) +#define SCG_APLL_OVRD_APLLCLKEN_OVRD_MASK (0x01 << SCG_APLL_OVRD_APLLCLKEN_OVRD_SHIFT) +#define SCG_APLL_OVRD_APLLCLKEN_OVRD(x) (((x) << SCG_APLL_OVRD_APLLCLKEN_OVRD_SHIFT) & SCG_APLL_OVRD_APLLCLKEN_OVRD_MASK) + +#define SCG_APLL_OVRD_APLL_OVRD_EN_SHIFT (31) +#define SCG_APLL_OVRD_APLL_OVRD_EN_MASK (0x01 << SCG_APLL_OVRD_APLL_OVRD_EN_SHIFT) +#define SCG_APLL_OVRD_APLL_OVRD_EN(x) (((x) << SCG_APLL_OVRD_APLL_OVRD_EN_SHIFT) & SCG_APLL_OVRD_APLL_OVRD_EN_MASK) + +/* System PLL Control Status Register */ + +#define SCG_SPLLCSR_SPLLEN (1 << 0) /* Bit 0: System PLL Enable */ +#define SCG_SPLLCSR_SPLLCM (1 << 16) /* Bit 16: System PLL Clock Monitor */ +#define SCG_SPLLCSR_SPLLCMRE (1 << 17) /* Bit 17: System PLL Clock Monitor Reset Enable */ +#define SCG_SPLLCSR_LK (1 << 23) /* Bit 23: Lock Register */ +#define SCG_SPLLCSR_SPLLVLD (1 << 24) /* Bit 24: System PLL Valid */ +#define SCG_SPLLCSR_SPLLSEL (1 << 25) /* Bit 25: System PLL Selected */ +#define SCG_SPLLCSR_SPLLERR (1 << 26) /* Bit 65: System PLL Clock Error */ + +/* System PLL Divide Register */ + +#define SCG_SPLLDIV_SPLLDIV1_SHIFT (0) /* Bits 0-2: System PLL Clock Divide 1 */ +#define SCG_SPLLDIV_SPLLDIV1_MASK (7 << SCG_SPLLDIV_SPLLDIV1_SHIFT) +# define SCG_SPLLDIV_SPLLDIV1(n) ((uint32_t)(n) << SCG_SPLLDIV_SPLLDIV1_SHIFT) +# define SCG_SPLLDIV_SPLLDIV1_DISABLE (0 << SCG_SPLLDIV_SPLLDIV1_SHIFT) /* Output disabled */ +# define SCG_SPLLDIV_SPLLDIV1_DIV1 (1 << SCG_SPLLDIV_SPLLDIV1_SHIFT) /* Divide by 1 */ +# define SCG_SPLLDIV_SPLLDIV1_DIV2 (2 << SCG_SPLLDIV_SPLLDIV1_SHIFT) /* Divide by 2 */ +# define SCG_SPLLDIV_SPLLDIV1_DIV4 (3 << SCG_SPLLDIV_SPLLDIV1_SHIFT) /* Divide by 4 */ +# define SCG_SPLLDIV_SPLLDIV1_DIV8 (4 << SCG_SPLLDIV_SPLLDIV1_SHIFT) /* Divide by 8 */ +# define SCG_SPLLDIV_SPLLDIV1_DIV16 (5 << SCG_SPLLDIV_SPLLDIV1_SHIFT) /* Divide by 16 */ +# define SCG_SPLLDIV_SPLLDIV1_DIV32 (6 << SCG_SPLLDIV_SPLLDIV1_SHIFT) /* Divide by 32 */ +# define SCG_SPLLDIV_SPLLDIV1_DIV64 (7 << SCG_SPLLDIV_SPLLDIV1_SHIFT) /* Divide by 64 */ + +#define SCG_SPLLDIV_SPLLDIV2_SHIFT (8) /* Bits 8-10: System PLL Clock Divide 2 */ +#define SCG_SPLLDIV_SPLLDIV2_MASK (7 << SCG_SPLLDIV_SPLLDIV2_SHIFT) +# define SCG_SPLLDIV_SPLLDIV2(n) ((uint32_t)(n) << SCG_SPLLDIV_SPLLDIV2_SHIFT) +# define SCG_SPLLDIV_SPLLDIV2_DISABLE (0 << SCG_SPLLDIV_SPLLDIV2_SHIFT) /* Output disabled */ +# define SCG_SPLLDIV_SPLLDIV2_DIV1 (1 << SCG_SPLLDIV_SPLLDIV2_SHIFT) /* Divide by 1 */ +# define SCG_SPLLDIV_SPLLDIV2_DIV2 (2 << SCG_SPLLDIV_SPLLDIV2_SHIFT) /* Divide by 2 */ +# define SCG_SPLLDIV_SPLLDIV2_DIV4 (3 << SCG_SPLLDIV_SPLLDIV2_SHIFT) /* Divide by 4 */ +# define SCG_SPLLDIV_SPLLDIV2_DIV8 (4 << SCG_SPLLDIV_SPLLDIV2_SHIFT) /* Divide by 8 */ +# define SCG_SPLLDIV_SPLLDIV2_DIV16 (5 << SCG_SPLLDIV_SPLLDIV2_SHIFT) /* Divide by 16 */ +# define SCG_SPLLDIV_SPLLDIV2_DIV32 (6 << SCG_SPLLDIV_SPLLDIV2_SHIFT) /* Divide by 32 */ +# define SCG_SPLLDIV_SPLLDIV2_DIV64 (7 << SCG_SPLLDIV_SPLLDIV2_SHIFT) /* Divide by 64 */ + +/* System PLL Configuration Register */ + +#define SCG_SPLLCFG_PREDIV_SHIFT (8) /* Bits 8-10: PLL Reference Clock Divider */ +#define SCG_SPLLCFG_PREDIV_MASK (7 << SCG_SPLLCFG_PREDIV_SHIFT) +# define SCG_SPLLCFG_PREDIV(n) ((uint32_t)((n) - 1) << SCG_SPLLCFG_PREDIV_SHIFT) /* n=1..8 */ + +#define SCG_SPLLCFG_MULT_SHIFT (16) /* Bits 16-20: System PLL Multiplier */ +#define SCG_SPLLCFG_MULT_MASK (31 << SCG_SPLLCFG_MULT_SHIFT) +# define SCG_SPLLCFG_MULT(n) ((uint32_t)((n) - 16) << SCG_SPLLCFG_MULT_SHIFT) /* n=16..47 */ + +/* LDO Control and Status Register */ + +#define SCG_LDOCSR_LDOEN (1 << 0) + +#endif /* __ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_SCG_H */ diff --git a/arch/arm/src/mcx-nxxx/hardware/nxxx_spc.h b/arch/arm/src/mcx-nxxx/hardware/nxxx_spc.h new file mode 100644 index 0000000000000..b1e3bb687bc61 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/hardware/nxxx_spc.h @@ -0,0 +1,495 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/hardware/nxxx_spc.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_SPC_H +#define ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_SPC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NXXX_SPC_VERID (NXXX_SPC0_BASE + 0x0000) /* Version ID */ +#define NXXX_SPC_SC (NXXX_SPC0_BASE + 0x0010) /* Status Control */ +#define NXXX_SPC_CNTRL (NXXX_SPC0_BASE + 0x0014) /* SPC Regulator Control */ +#define NXXX_SPC_LPREQ_CFG (NXXX_SPC0_BASE + 0x001C) /* Low-Power Request Configuration */ +#define NXXX_SPC_PD_STATUS0 (NXXX_SPC0_BASE + 0x0030) /* SPC Power Domain Mode Status */ +#define NXXX_SPC_PD_STATUS1 (NXXX_SPC0_BASE + 0x0034) /* SPC Power Domain Mode Status */ +#define NXXX_SPC_SRAMCTL (NXXX_SPC0_BASE + 0x0040) /* SRAM Control */ +#define NXXX_SPC_ACTIVE_CFG (NXXX_SPC0_BASE + 0x0100) /* Active Power Mode Configuration */ +#define NXXX_SPC_ACTIVE_CFG1 (NXXX_SPC0_BASE + 0x0104) /* Active Power Mode Configuration 1 */ +#define NXXX_SPC_LP_CFG (NXXX_SPC0_BASE + 0x0108) /* Low-Power Mode Configuration */ +#define NXXX_SPC_LP_CFG1 (NXXX_SPC0_BASE + 0x010C) /* Low Power Mode Configuration 1 */ +#define NXXX_SPC_LPWKUP_DELAY (NXXX_SPC0_BASE + 0x0120) /* Low Power Wake-Up Delay */ +#define NXXX_SPC_ACTIVE_VDELAY (NXXX_SPC0_BASE + 0x0124) /* Active Voltage Trim Delay */ +#define NXXX_SPC_VD_STAT (NXXX_SPC0_BASE + 0x0130) /* Voltage Detect Status */ +#define NXXX_SPC_VD_CORE_CFG (NXXX_SPC0_BASE + 0x0134) /* Core Voltage Detect Configuration */ +#define NXXX_SPC_VD_SYS_CFG (NXXX_SPC0_BASE + 0x0138) /* System Voltage Detect Configuration */ +#define NXXX_SPC_VD_IO_CFG (NXXX_SPC0_BASE + 0x013C) /* IO Voltage Detect Configuration */ +#define NXXX_SPC_EVD_CFG (NXXX_SPC0_BASE + 0x0140) /* External Voltage Domain Configuration */ +#define NXXX_SPC_GLITCH_DETECT_SC (NXXX_SPC0_BASE + 0x0144) /* Glitch Detect Status Control */ +#define NXXX_SPC_CORELDO_CFG (NXXX_SPC0_BASE + 0x0300) /* LDO_CORE Configuration */ +#define NXXX_SPC_SYSLDO_CFG (NXXX_SPC0_BASE + 0x0400) /* LDO_SYS Configuration */ +#define NXXX_SPC_DCDC_CFG (NXXX_SPC0_BASE + 0x0500) /* DCDC Configuration */ +#define NXXX_SPC_DCDC_BURST_CFG (NXXX_SPC0_BASE + 0x0504) /* DCDC Burst Configuration */ + +/* Status Control (SC) */ + +#define SPC_SC_BUSY_SHIFT (0) +#define SPC_SC_BUSY_MASK (0x01 << SPC_SC_BUSY_SHIFT) +#define SPC_SC_BUSY(x) (((x) << SPC_SC_BUSY_SHIFT) & SPC_SC_BUSY_MASK) + +#define SPC_SC_SPC_LP_REQ_SHIFT (1) +#define SPC_SC_SPC_LP_REQ_MASK (0x01 < SPC_SC_SPC_LP_REQ_SHIFT) +#define SPC_SC_SPC_LP_REQ(x) ((((x) << SPC_SC_SPC_LP_REQ_SHIFT) & SPC_SC_SPC_LP_REQ_MASK) + +#define SPC_SC_SPC_LP_MODE_SHIFT (4) +#define SPC_SC_SPC_LP_MODE_MASK (0x0f << SPC_SC_SPC_LP_MODE_SHIFT) +#define SPC_SC_SPC_LP_MODE(x) (((x) << SPC_SC_SPC_LP_MODE_SHIFT) & SPC_SC_SPC_LP_MODE_MASK) + +#define SPC_SC_ISO_CLR_SHIFT (16) +#define SPC_SC_ISO_CLR_MASK (0x03 << SPC_SC_ISO_CLR_SHIFT) +#define SPC_SC_ISO_CLR(x) (((x) << SPC_SC_ISO_CLR_SHIFT) & SPC_SC_ISO_CLR_MASK) + +/* Regulator Control (CNTRL) */ + +#define SPC_CNTRL_CORELDO_EN_SHIFT (0) +#define SPC_CNTRL_CORELDO_EN_MASK (0x01 << SPC_CNTRL_CORELDO_EN_SHIFT) +#define SPC_CNTRL_CORELDO_EN(x) (((x) << SPC_CNTRL_CORELDO_EN_SHIFT) & SPC_CNTRL_CORELDO_EN_MASK) + +#define SPC_CNTRL_SYSLDO_EN_SHIFT (1) +#define SPC_CNTRL_SYSLDO_EN_MASK (0x01 << SPC_CNTRL_SYSLDO_EN_SHIFT) +#define SPC_CNTRL_SYSLDO_EN(x) (((x) << SPC_CNTRL_SYSLDO_EN_SHIFT) & SPC_CNTRL_SYSLDO_EN_MASK) + +#define SPC_CNTRL_DCDC_EN_SHIFT (2) +#define SPC_CNTRL_DCDC_EN_MASK (0x01 << SPC_CNTRL_DCDC_EN_SHIFT) +#define SPC_CNTRL_DCDC_EN(x) (((x) << SPC_CNTRL_DCDC_EN_SHIFT) & SPC_CNTRL_DCDC_EN_MASK) + +/* Low-Power Request Configuration (LPREQ_CFG) */ + +#define SPC_LPREQ_CFG_LPREQOE_SHIFT (0) +#define SPC_LPREQ_CFG_LPREQOE_MASK (0x01 << SPC_LPREQ_CFG_LPREQOE_SHIFT) +#define SPC_LPREQ_CFG_LPREQOE(x) (((x) << SPC_LPREQ_CFG_LPREQOE_SHIFT) & SPC_LPREQ_CFG_LPREQOE_MASK) + +#define SPC_LPREQ_CFG_LPREQPOL_SHIFT (1) +#define SPC_LPREQ_CFG_LPREQPOL_MASK (0x01) +#define SPC_LPREQ_CFG_LPREQPOL(x) (((x) << SPC_LPREQ_CFG_LPREQPOL_SHIFT) & SPC_LPREQ_CFG_LPREQPOL_MASK) + +#define SPC_LPREQ_CFG_LPREQOV_SHIFT (2) +#define SPC_LPREQ_CFG_LPREQOV_MASK (0x03 << SPC_LPREQ_CFG_LPREQOV_SHIFT) +#define SPC_LPREQ_CFG_LPREQOV(x) (((x) << SPC_LPREQ_CFG_LPREQOV_SHIFT) & SPC_LPREQ_CFG_LPREQOV_MASK) + +/* Power Domain Mode Status (PD_STATUS) */ + +#define SPC_PD_STATUS_PWR_REQ_STATUS_SHIFT (0) +#define SPC_PD_STATUS_PWR_REQ_STATUS_MASK (0x01 << SPC_PD_STATUS_PWR_REQ_STATUS_SHIFT) +#define SPC_PD_STATUS_PWR_REQ_STATUS(x) (((x) << SPC_PD_STATUS_PWR_REQ_STATUS_SHIFT) & SPC_PD_STATUS_PWR_REQ_STATUS_MASK) + +#define SPC_PD_STATUS_PD_LP_REQ_SHIFT (4) +#define SPC_PD_STATUS_PD_LP_REQ_MASK (0x01 << SPC_PD_STATUS_PD_LP_REQ_SHIFT) +#define SPC_PD_STATUS_PD_LP_REQ(x) (((x) << SPC_PD_STATUS_PD_LP_REQ_SHIFT) & SPC_PD_STATUS_PD_LP_REQ_MASK) + +#define SPC_PD_STATUS_LP_MODE_SHIFT (8) +#define SPC_PD_STATUS_LP_MODE_MASK (0x0f << SPC_PD_STATUS_LP_MODE_SHIFT) +#define SPC_PD_STATUS_LP_MODE(x) (((x) << SPC_PD_STATUS_LP_MODE_SHIFT) & SPC_PD_STATUS_LP_MODE_MASK) + +/* SRAM Control (SRAMCTL) */ + +#define SPC_SRAMCTL_VSM_SHIFT (0) +#define SPC_SRAMCTL_VSM_MASK (0x03 << SPC_SRAMCTL_VSM_SHIFT) +#define SPC_SRAMCTL_VSM(x) (((x) << SPC_SRAMCTL_VSM_SHIFT) & SPC_SRAMCTL_VSM_MASK) + +#define SPC_SRAM1V0 (0x01) /* SRAM configured for 1.0V operation. */ +#define SPC_SRAM1V1 (0x02) /* SRAM configured for 1.1V operation. */ +#define SPC_SRAM1V2 (0x03) /* SRAM configured for 1.2V operation. */ + +#define SPC_SRAMCTL_REQ_SHIFT (30) +#define SPC_SRAMCTL_REQ_MASK (0x01 << SPC_SRAMCTL_REQ_SHIFT) +#define SPC_SRAMCTL_REQ(x) (((x) << SPC_SRAMCTL_REQ_SHIFT) & SPC_SRAMCTL_REQ_MASK) + +#define SPC_SRAMCTL_ACK_SHIFT (31) +#define SPC_SRAMCTL_ACK_MASK (0x01 << SPC_SRAMCTL_ACK_SHIFT) +#define SPC_SRAMCTL_ACK(x) (((x) << SPC_SRAMCTL_ACK_SHIFT) & SPC_SRAMCTL_ACK_MASK) + +/* Active Power Mode Configuration (ACTIVE_CFG) */ + +#define SPC_ACTIVE_CFG_CORELDO_VDD_DS_SHIFT (0) +#define SPC_ACTIVE_CFG_CORELDO_VDD_DS_MASK (0x01 << SPC_ACTIVE_CFG_CORELDO_VDD_DS_SHIFT) +#define SPC_ACTIVE_CFG_CORELDO_VDD_DS(x) (((x) << SPC_ACTIVE_CFG_CORELDO_VDD_DS_SHIFT) & SPC_ACTIVE_CFG_CORELDO_VDD_DS_MASK) + +#define SPC_ACTIVE_CFG_CORELDO_VDD_LVL_SHIFT (2) +#define SPC_ACTIVE_CFG_CORELDO_VDD_LVL_MASK (0x03 << SPC_ACTIVE_CFG_CORELDO_VDD_LVL_SHIFT) +#define SPC_ACTIVE_CFG_CORELDO_VDD_LVL(x) (((x) << SPC_ACTIVE_CFG_CORELDO_VDD_LVL_SHIFT) & SPC_ACTIVE_CFG_CORELDO_VDD_LVL_MASK) + +#define SPC_ACTIVE_CFG_SYSLDO_VDD_DS_SHIFT (4) +#define SPC_ACTIVE_CFG_SYSLDO_VDD_DS_MASK (0x01 << SPC_ACTIVE_CFG_SYSLDO_VDD_DS_SHIFT) +#define SPC_ACTIVE_CFG_SYSLDO_VDD_DS(x) (((x) << SPC_ACTIVE_CFG_SYSLDO_VDD_DS_SHIFT) & SPC_ACTIVE_CFG_SYSLDO_VDD_DS_MASK) + +#define SPC_ACTIVE_CFG_SYSLDO_VDD_LVL_SHIFT (6) +#define SPC_ACTIVE_CFG_SYSLDO_VDD_LVL_MASK (0x01 << SPC_ACTIVE_CFG_SYSLDO_VDD_LVL_SHIFT) +#define SPC_ACTIVE_CFG_SYSLDO_VDD_LVL(x) (((x) << SPC_ACTIVE_CFG_SYSLDO_VDD_LVL_SHIFT) & SPC_ACTIVE_CFG_SYSLDO_VDD_LVL_MASK) + +#define SPC_ACTIVE_CFG_DCDC_VDD_DS_SHIFT (8) +#define SPC_ACTIVE_CFG_DCDC_VDD_DS_MASK (0x03 << SPC_ACTIVE_CFG_DCDC_VDD_DS_SHIFT) +#define SPC_ACTIVE_CFG_DCDC_VDD_DS(x) (((x) << SPC_ACTIVE_CFG_DCDC_VDD_DS_SHIFT) & SPC_ACTIVE_CFG_DCDC_VDD_DS_MASK) + +#define SPC_DCDC_PULSEREFRESHMODE (0) /* DCDC_CORE Regulator Drive Strength set to Pulse Refresh Mode */ +#define SPC_DCDC_LOWDRIVESTRENGTH (1) /* DCDC_CORE regulator Drive Strength set to low. */ +#define SPC_DCDC_NORMALDRIVESTRENGTH (2) /* DCDC_CORE regulator Drive Strength set to Normal. */ + +#define SPC_ACTIVE_CFG_DCDC_VDD_LVL_SHIFT (10) +#define SPC_ACTIVE_CFG_DCDC_VDD_LVL_MASK (0x03 << SPC_ACTIVE_CFG_DCDC_VDD_LVL_SHIFT) +#define SPC_ACTIVE_CFG_DCDC_VDD_LVL(x) (((x) << SPC_ACTIVE_CFG_DCDC_VDD_LVL_SHIFT) & SPC_ACTIVE_CFG_DCDC_VDD_LVL_MASK) + +#define SPC_DCDC_RETENTIONVOLTAGE (0) /* DCDC_CORE Regulator regulate to retention Voltage */ +#define SPC_DCDC_MIDVOLTAGE (1) /* DCDC_CORE Regulator regulate to Mid Voltage(1.0V). */ +#define SPC_DCDC_NORMALVOLTAGE (2) /* DCDC_CORE Regulator regulate to Normal Voltage(1.1V). */ +#define SPC_DCDC_OVERDRIVEVOLTAGE (3) /* DCDC_CORE Regulator regulate to Safe-Mode Voltage(1.2V). */ + +#define SPC_ACTIVE_CFG_GLITCH_DETECT_DISABLE_SHIFT (12) +#define SPC_ACTIVE_CFG_GLITCH_DETECT_DISABLE_MASK (0x01 << SPC_ACTIVE_CFG_GLITCH_DETECT_DISABLE_SHIFT) +#define SPC_ACTIVE_CFG_GLITCH_DETECT_DISABLE(x) (((x) << SPC_ACTIVE_CFG_GLITCH_DETECT_DISABLE_SHIFT) & SPC_ACTIVE_CFG_GLITCH_DETECT_DISABLE_MASK) + +#define SPC_ACTIVE_CFG_LPBUFF_EN_SHIFT (18) +#define SPC_ACTIVE_CFG_LPBUFF_EN_MASK (0x01 << SPC_ACTIVE_CFG_LPBUFF_EN_SHIFT) +#define SPC_ACTIVE_CFG_LPBUFF_EN(x) (((x) << SPC_ACTIVE_CFG_LPBUFF_EN_SHIFT) & SPC_ACTIVE_CFG_LPBUFF_EN_MASK) + +#define SPC_ACTIVE_CFG_BGMODE_SHIFT (20) +#define SPC_ACTIVE_CFG_BGMODE_MASK (0x03 << SPC_ACTIVE_CFG_BGMODE_SHIFT) +#define SPC_ACTIVE_CFG_BGMODE(x) (((x) << SPC_ACTIVE_CFG_BGMODE_SHIFT) & SPC_ACTIVE_CFG_BGMODE_MASK) + +#define SPC_ACTIVE_CFG_VDD_VD_DISABLE_SHIFT (23) +#define SPC_ACTIVE_CFG_VDD_VD_DISABLE_MASK (0x01 << SPC_ACTIVE_CFG_VDD_VD_DISABLE_SHIFT) +#define SPC_ACTIVE_CFG_VDD_VD_DISABLE(x) (((x) << SPC_ACTIVE_CFG_VDD_VD_DISABLE_SHIFT) & SPC_ACTIVE_CFG_VDD_VD_DISABLE_MASK) + +#define SPC_ACTIVE_CFG_CORE_LVDE_SHIFT (24) +#define SPC_ACTIVE_CFG_CORE_LVDE_MASK (0x01 << SPC_ACTIVE_CFG_CORE_LVDE_SHIFT) +#define SPC_ACTIVE_CFG_CORE_LVDE(x) (((x) << SPC_ACTIVE_CFG_CORE_LVDE_SHIFT) & SPC_ACTIVE_CFG_CORE_LVDE_MASK) + +#define SPC_ACTIVE_CFG_SYS_LVDE_SHIFT (25) +#define SPC_ACTIVE_CFG_SYS_LVDE_MASK (0x01 << SPC_ACTIVE_CFG_SYS_LVDE_SHIFT) +#define SPC_ACTIVE_CFG_SYS_LVDE(x) (((x) << SPC_ACTIVE_CFG_SYS_LVDE_SHIFT) & SPC_ACTIVE_CFG_SYS_LVDE_MASK) + +#define SPC_ACTIVE_CFG_IO_LVDE_SHIFT (26) +#define SPC_ACTIVE_CFG_IO_LVDE_MASK (0x01) +#define SPC_ACTIVE_CFG_IO_LVDE(x) (((x) << SPC_ACTIVE_CFG_IO_LVDE_SHIFT) & SPC_ACTIVE_CFG_IO_LVDE_MASK) + +#define SPC_ACTIVE_CFG_CORE_HVDE_SHIFT (27) +#define SPC_ACTIVE_CFG_CORE_HVDE_MASK (0x01 << SPC_ACTIVE_CFG_CORE_HVDE_SHIFT) +#define SPC_ACTIVE_CFG_CORE_HVDE(x) (((x) << SPC_ACTIVE_CFG_CORE_HVDE_SHIFT) & SPC_ACTIVE_CFG_CORE_HVDE_MASK) + +#define SPC_ACTIVE_CFG_SYS_HVDE_SHIFT (28) +#define SPC_ACTIVE_CFG_SYS_HVDE_MASK (0x01 << SPC_ACTIVE_CFG_SYS_HVDE_SHIFT) +#define SPC_ACTIVE_CFG_SYS_HVDE(x) (((x) << SPC_ACTIVE_CFG_SYS_HVDE_SHIFT) & SPC_ACTIVE_CFG_SYS_HVDE_MASK) + +#define SPC_ACTIVE_CFG_IO_HVDE_SHIFT (29) +#define SPC_ACTIVE_CFG_IO_HVDE_MASK (0x01) +#define SPC_ACTIVE_CFG_IO_HVDE(x) (((x) << SPC_ACTIVE_CFG_IO_HVDE_SHIFT) & SPC_ACTIVE_CFG_IO_HVDE_MASK) + +/* Active Power Mode Configuration 1 (ACTIVE_CFG1) */ + +#define SPC_ACTIVE_CFG1_SOC_CNTRL_SHIFT (0) +#define SPC_ACTIVE_CFG1_SOC_CNTRL_MASK (0xffffffff << SPC_ACTIVE_CFG1_SOC_CNTRL_SHIFT) +#define SPC_ACTIVE_CFG1_SOC_CNTRL(x) (((x) << SPC_ACTIVE_CFG1_SOC_CNTRL_SHIFT) & SPC_ACTIVE_CFG1_SOC_CNTRL_MASK) + +/* Low-Power Mode Configuration (LP_CFG) */ + +#define SPC_LP_CFG_CORELDO_VDD_DS_SHIFT (0) +#define SPC_LP_CFG_CORELDO_VDD_DS_MASK (0x01 << SPC_LP_CFG_CORELDO_VDD_DS_SHIFT) +#define SPC_LP_CFG_CORELDO_VDD_DS(x) (((x) << SPC_LP_CFG_CORELDO_VDD_DS_SHIFT) & SPC_LP_CFG_CORELDO_VDD_DS_MASK) + +#define SPC_CORELDO_LOWDRIVESTRENGTH (0) /* Core LDO VDD regulator Drive Strength set to low. */ +#define SPC_CORELDO_NORMALDRIVESTRENGTH (1) /* Core LDO VDD regulator Drive Strength set to Normal. */ + +#define SPC_LP_CFG_CORELDO_VDD_LVL_SHIFT (2) +#define SPC_LP_CFG_CORELDO_VDD_LVL_MASK (0x3 << SPC_LP_CFG_CORELDO_VDD_LVL_SHIFT) +#define SPC_LP_CFG_CORELDO_VDD_LVL(x) (((x) << SPC_LP_CFG_CORELDO_VDD_LVL_SHIFT) & SPC_LP_CFG_CORELDO_VDD_LVL_MASK) + +#define SPC_CORELDO_RETENTIONVOLTAGE (0) /* Core LDO VDD regulator regulate to retention voltage. */ +#define SPC_CORELDO_MIDDRIVEVOLTAGE (1) /* Core LDO VDD regulator regulate to Mid Drive Voltage. */ +#define SPC_CORELDO_NORMALVOLTAGE (2) /* Core LDO VDD regulator regulate to Normal Voltage. */ +#define SPC_CORELDO_OVERDRIVEVOLTAGE (3) /* Core LDO VDD regulator regulate to overdrive Voltage. */ + +#define SPC_LP_CFG_SYSLDO_VDD_DS_SHIFT (4) +#define SPC_LP_CFG_SYSLDO_VDD_DS_MASK (0x01 << SPC_LP_CFG_SYSLDO_VDD_DS_SHIFT) +#define SPC_LP_CFG_SYSLDO_VDD_DS(x) (((x) << SPC_LP_CFG_SYSLDO_VDD_DS_SHIFT) & SPC_LP_CFG_SYSLDO_VDD_DS_MASK) + +#define SPC_LP_CFG_DCDC_VDD_DS_SHIFT (8) +#define SPC_LP_CFG_DCDC_VDD_DS_MASK (0x03 << SPC_LP_CFG_DCDC_VDD_DS_SHIFT) +#define SPC_LP_CFG_DCDC_VDD_DS(x) (((x) << SPC_LP_CFG_DCDC_VDD_DS_SHIFT) & SPC_LP_CFG_DCDC_VDD_DS_MASK) + +#define SPC_LP_CFG_DCDC_VDD_LVL_SHIFT (10) +#define SPC_LP_CFG_DCDC_VDD_LVL_MASK (0x03 << SPC_LP_CFG_DCDC_VDD_LVL_SHIFT) +#define SPC_LP_CFG_DCDC_VDD_LVL(x) (((x) << SPC_LP_CFG_DCDC_VDD_LVL_SHIFT) & SPC_LP_CFG_DCDC_VDD_LVL_MASK) + +#define SPC_LP_CFG_GLITCH_DETECT_DISABLE_SHIFT (12) +#define SPC_LP_CFG_GLITCH_DETECT_DISABLE_MASK (0x01 << SPC_LP_CFG_GLITCH_DETECT_DISABLE_SHIFT) +#define SPC_LP_CFG_GLITCH_DETECT_DISABLE(x) (((x) << SPC_LP_CFG_GLITCH_DETECT_DISABLE_SHIFT) & SPC_LP_CFG_GLITCH_DETECT_DISABLE_MASK) + +#define SPC_LP_CFG_COREVDD_IVS_EN_SHIFT (17) +#define SPC_LP_CFG_COREVDD_IVS_EN_MASK (0x01 << SPC_LP_CFG_COREVDD_IVS_EN_SHIFT) +#define SPC_LP_CFG_COREVDD_IVS_EN(x) (((x) << SPC_LP_CFG_COREVDD_IVS_EN_SHIFT) & SPC_LP_CFG_COREVDD_IVS_EN_MASK) + +#define SPC_LP_CFG_LPBUFF_EN_SHIFT (18) +#define SPC_LP_CFG_LPBUFF_EN_MASK (0x01 << SPC_LP_CFG_LPBUFF_EN_SHIFT) +#define SPC_LP_CFG_LPBUFF_EN(x) (((x) << SPC_LP_CFG_LPBUFF_EN_SHIFT) & SPC_LP_CFG_LPBUFF_EN_MASK) + +#define SPC_LP_CFG_BGMODE_SHIFT (20) +#define SPC_LP_CFG_BGMODE_MASK (0x03 << SPC_LP_CFG_BGMODE_SHIFT) +#define SPC_LP_CFG_BGMODE(x) (((x) << SPC_LP_CFG_BGMODE_SHIFT) & SPC_LP_CFG_BGMODE_MASK) + +#define SPC_LP_CFG_LP_IREFEN_SHIFT (23) +#define SPC_LP_CFG_LP_IREFEN_MASK (0x01 << SPC_LP_CFG_LP_IREFEN_SHIFT) +#define SPC_LP_CFG_LP_IREFEN(x) (((x) << SPC_LP_CFG_LP_IREFEN_SHIFT) & SPC_LP_CFG_LP_IREFEN_MASK) + +#define SPC_LP_CFG_CORE_LVDE_SHIFT (24) +#define SPC_LP_CFG_CORE_LVDE_MASK (0x01 << SPC_LP_CFG_CORE_LVDE_SHIFT) +#define SPC_LP_CFG_CORE_LVDE(x) (((x) << SPC_LP_CFG_CORE_LVDE_SHIFT) & SPC_LP_CFG_CORE_LVDE_MASK) + +#define SPC_LP_CFG_SYS_LVDE_SHIFT (25) +#define SPC_LP_CFG_SYS_LVDE_MASK (0x01 << SPC_LP_CFG_SYS_LVDE_SHIFT) +#define SPC_LP_CFG_SYS_LVDE(x) (((x) << SPC_LP_CFG_SYS_LVDE_SHIFT) & SPC_LP_CFG_SYS_LVDE_MASK) + +#define SPC_LP_CFG_IO_LVDE_SHIFT (26) +#define SPC_LP_CFG_IO_LVDE_MASK (0x01 << SPC_LP_CFG_IO_LVDE_SHIFT) +#define SPC_LP_CFG_IO_LVDE(x) (((x) << SPC_LP_CFG_IO_LVDE_SHIFT) & SPC_LP_CFG_IO_LVDE_MASK) + +#define SPC_LP_CFG_CORE_HVDE_SHIFT (27) +#define SPC_LP_CFG_CORE_HVDE_MASK (0x01 << SPC_LP_CFG_CORE_HVDE_SHIFT) +#define SPC_LP_CFG_CORE_HVDE(x) (((x) << SPC_LP_CFG_CORE_HVDE_SHIFT) & SPC_LP_CFG_CORE_HVDE_MASK) + +#define SPC_LP_CFG_SYS_HVDE_SHIFT (28) +#define SPC_LP_CFG_SYS_HVDE_MASK (0x01 << SPC_LP_CFG_SYS_HVDE_SHIFT) +#define SPC_LP_CFG_SYS_HVDE(x) (((x) << SPC_LP_CFG_SYS_HVDE_SHIFT) & SPC_LP_CFG_SYS_HVDE_MASK) + +#define SPC_LP_CFG_IO_HVDE_SHIFT (29) +#define SPC_LP_CFG_IO_HVDE_MASK (0x01 << SPC_LP_CFG_IO_HVDE_SHIFT) +#define SPC_LP_CFG_IO_HVDE(x) (((x) << SPC_LP_CFG_IO_HVDE_SHIFT) & SPC_LP_CFG_IO_HVDE_MASK) + +/* Low Power Mode Configuration 1 (LP_CFG1) */ + +#define SPC_LP_CFG1_SOC_CNTRL_SHIFT (0) +#define SPC_LP_CFG1_SOC_CNTRL_MASK (0xffffffff << SPC_LP_CFG1_SOC_CNTRL_SHIFT) +#define SPC_LP_CFG1_SOC_CNTRL(x) (((x) << SPC_LP_CFG1_SOC_CNTRL_SHIFT) & SPC_LP_CFG1_SOC_CNTRL_MASK) + +/* Low Power Wake-Up Delay (LPWKUP_DELAY) */ + +#define SPC_LPWKUP_DELAY_LPWKUP_DELAY_SHIFT (0) +#define SPC_LPWKUP_DELAY_LPWKUP_DELAY_MASK (0xffff << SPC_LPWKUP_DELAY_LPWKUP_DELAY_SHIFT) +#define SPC_LPWKUP_DELAY_LPWKUP_DELAY(x) (((x) << SPC_LPWKUP_DELAY_LPWKUP_DELAY_SHIFT) & SPC_LPWKUP_DELAY_LPWKUP_DELAY_MASK) + +/* Active Voltage Trim Delay (ACTIVE_VDELAY) */ + +#define SPC_ACTIVE_VDELAY_ACTIVE_VDELAY_SHIFT (0) +#define SPC_ACTIVE_VDELAY_ACTIVE_VDELAY_MASK (0xffff << SPC_ACTIVE_VDELAY_ACTIVE_VDELAY_SHIFT) +#define SPC_ACTIVE_VDELAY_ACTIVE_VDELAY(x) (((x) << SPC_ACTIVE_VDELAY_ACTIVE_VDELAY_SHIFT) & SPC_ACTIVE_VDELAY_ACTIVE_VDELAY_MASK) + +/* Voltage Detect Status (VD_STAT) */ + +#define SPC_VD_STAT_COREVDD_LVDF_SHIFT (0) +#define SPC_VD_STAT_COREVDD_LVDF_MASK (0x01 << SPC_VD_STAT_COREVDD_LVDF_SHIFT) +#define SPC_VD_STAT_COREVDD_LVDF(x) (((x) << SPC_VD_STAT_COREVDD_LVDF_SHIFT) & SPC_VD_STAT_COREVDD_LVDF_MASK) + +#define SPC_VD_STAT_SYSVDD_LVDF_SHIFT (1) +#define SPC_VD_STAT_SYSVDD_LVDF_MASK (0x01 << SPC_VD_STAT_SYSVDD_LVDF_SHIFT) +#define SPC_VD_STAT_SYSVDD_LVDF(x) (((x) << SPC_VD_STAT_SYSVDD_LVDF_SHIFT) & SPC_VD_STAT_SYSVDD_LVDF_MASK) + +#define SPC_VD_STAT_IOVDD_LVDF_SHIFT (2) +#define SPC_VD_STAT_IOVDD_LVDF_MASK (0x01 << SPC_VD_STAT_IOVDD_LVDF_SHIFT) +#define SPC_VD_STAT_IOVDD_LVDF(x) (((x) << SPC_VD_STAT_IOVDD_LVDF_SHIFT) & SPC_VD_STAT_IOVDD_LVDF_MASK) + +#define SPC_VD_STAT_COREVDD_HVDF_SHIFT (4) +#define SPC_VD_STAT_COREVDD_HVDF_MASK (0x01 << SPC_VD_STAT_COREVDD_HVDF_SHIFT) +#define SPC_VD_STAT_COREVDD_HVDF(x) (((x) << SPC_VD_STAT_COREVDD_HVDF_SHIFT) & SPC_VD_STAT_COREVDD_HVDF_MASK) + +#define SPC_VD_STAT_SYSVDD_HVDF_SHIFT (5) +#define SPC_VD_STAT_SYSVDD_HVDF_MASK (0x01 << SPC_VD_STAT_SYSVDD_HVDF_SHIFT) +#define SPC_VD_STAT_SYSVDD_HVDF(x) (((x) << SPC_VD_STAT_SYSVDD_HVDF_SHIFT) & SPC_VD_STAT_SYSVDD_HVDF_MASK) + +#define SPC_VD_STAT_IOVDD_HVDF_SHIFT (6) +#define SPC_VD_STAT_IOVDD_HVDF_MASK (0x01 << SPC_VD_STAT_IOVDD_HVDF_SHIFT) +#define SPC_VD_STAT_IOVDD_HVDF(x) (((x) << SPC_VD_STAT_IOVDD_HVDF_SHIFT) & SPC_VD_STAT_IOVDD_HVDF_MASK) + +/* Core Voltage Detect Configuration (VD_CORE_CFG) */ + +#define SPC_VD_CORE_CFG_LVDRE_SHIFT (0) +#define SPC_VD_CORE_CFG_LVDRE_MASK (0x01 << SPC_VD_CORE_CFG_LVDRE_SHIFT) +#define SPC_VD_CORE_CFG_LVDRE(x) (((x) << SPC_VD_CORE_CFG_LVDRE_SHIFT) & SPC_VD_CORE_CFG_LVDRE_MASK) + +#define SPC_VD_CORE_CFG_LVDIE_SHIFT (1) +#define SPC_VD_CORE_CFG_LVDIE_MASK (0x01 << SPC_VD_CORE_CFG_LVDIE_SHIFT) +#define SPC_VD_CORE_CFG_LVDIE(x) (((x) << SPC_VD_CORE_CFG_LVDIE_SHIFT) & SPC_VD_CORE_CFG_LVDIE_MASK) + +#define SPC_VD_CORE_CFG_HVDRE_SHIFT (2) +#define SPC_VD_CORE_CFG_HVDRE_MASK (0x01 << SPC_VD_CORE_CFG_HVDRE_SHIFT) +#define SPC_VD_CORE_CFG_HVDRE(x) (((x) << SPC_VD_CORE_CFG_HVDRE_SHIFT) & SPC_VD_CORE_CFG_HVDRE_MASK) + +#define SPC_VD_CORE_CFG_HVDIE_SHIFT (3) +#define SPC_VD_CORE_CFG_HVDIE_MASK (0x01 << SPC_VD_CORE_CFG_HVDIE_SHIFT) +#define SPC_VD_CORE_CFG_HVDIE(x) (((x) << SPC_VD_CORE_CFG_HVDIE_SHIFT) & SPC_VD_CORE_CFG_HVDIE_MASK) + +#define SPC_VD_CORE_CFG_LOCK_SHIFT (16) +#define SPC_VD_CORE_CFG_LOCK_MASK (0x01 << SPC_VD_CORE_CFG_LOCK_SHIFT) +#define SPC_VD_CORE_CFG_LOCK(x) (((x) << SPC_VD_CORE_CFG_LOCK_SHIFT) & SPC_VD_CORE_CFG_LOCK_MASK) + +/* System Voltage Detect Configuration (VD_SYS_CFG) */ + +#define SPC_VD_SYS_CFG_LVDRE_SHIFT (0) +#define SPC_VD_SYS_CFG_LVDRE_MASK (0x01 << SPC_VD_SYS_CFG_LVDRE_SHIFT) +#define SPC_VD_SYS_CFG_LVDRE(x) (((x) << SPC_VD_SYS_CFG_LVDRE_SHIFT) & SPC_VD_SYS_CFG_LVDRE_MASK) + +#define SPC_VD_SYS_CFG_LVDIE_SHIFT (1) +#define SPC_VD_SYS_CFG_LVDIE_MASK (0x01 << SPC_VD_SYS_CFG_LVDIE_SHIFT) +#define SPC_VD_SYS_CFG_LVDIE(x) (((x) << SPC_VD_SYS_CFG_LVDIE_SHIFT) & SPC_VD_SYS_CFG_LVDIE_MASK) + +#define SPC_VD_SYS_CFG_HVDRE_SHIFT (2) +#define SPC_VD_SYS_CFG_HVDRE_MASK (0x01 << SPC_VD_SYS_CFG_HVDRE_SHIFT) +#define SPC_VD_SYS_CFG_HVDRE(x) (((x) << SPC_VD_SYS_CFG_HVDRE_SHIFT) & SPC_VD_SYS_CFG_HVDRE_MASK) + +#define SPC_VD_SYS_CFG_HVDIE_SHIFT (3) +#define SPC_VD_SYS_CFG_HVDIE_MASK (0x01 << SPC_VD_SYS_CFG_HVDIE_SHIFT) +#define SPC_VD_SYS_CFG_HVDIE(x) (((x) << SPC_VD_SYS_CFG_HVDIE_SHIFT) & SPC_VD_SYS_CFG_HVDIE_MASK) + +#define SPC_VD_SYS_CFG_LVSEL_SHIFT (8) +#define SPC_VD_SYS_CFG_LVSEL_MASK (0x01 << SPC_VD_SYS_CFG_LVSEL_SHIFT) +#define SPC_VD_SYS_CFG_LVSEL(x) (((x) << SPC_VD_SYS_CFG_LVSEL_SHIFT) & SPC_VD_SYS_CFG_LVSEL_MASK) + +#define SPC_VD_SYS_CFG_LOCK_SHIFT (16) +#define SPC_VD_SYS_CFG_LOCK_MASK (0x01 << SPC_VD_SYS_CFG_LOCK_SHIFT) +#define SPC_VD_SYS_CFG_LOCK(x) (((x) << SPC_VD_SYS_CFG_LOCK_SHIFT) & SPC_VD_SYS_CFG_LOCK_MASK) + +/* IO Voltage Detect Configuration (VD_IO_CFG) */ + +#define SPC_VD_IO_CFG_LVDRE_SHIFT (0) +#define SPC_VD_IO_CFG_LVDRE_MASK (0x01 << SPC_VD_IO_CFG_LVDRE_SHIFT) +#define SPC_VD_IO_CFG_LVDRE(x) (((x) << SPC_VD_IO_CFG_LVDRE_SHIFT) & SPC_VD_IO_CFG_LVDRE_MASK) + +#define SPC_VD_IO_CFG_LVDIE_SHIFT (1) +#define SPC_VD_IO_CFG_LVDIE_MASK (0x01 << SPC_VD_IO_CFG_LVDIE_SHIFT) +#define SPC_VD_IO_CFG_LVDIE(x) (((x) << SPC_VD_IO_CFG_LVDIE_SHIFT) & SPC_VD_IO_CFG_LVDIE_MASK) + +#define SPC_VD_IO_CFG_HVDRE_SHIFT (2) +#define SPC_VD_IO_CFG_HVDRE_MASK (0x01 << SPC_VD_IO_CFG_HVDRE_SHIFT) +#define SPC_VD_IO_CFG_HVDRE(x) (((x) << SPC_VD_IO_CFG_HVDRE_SHIFT) & SPC_VD_IO_CFG_HVDRE_MASK) + +#define SPC_VD_IO_CFG_HVDIE_SHIFT (3) +#define SPC_VD_IO_CFG_HVDIE_MASK (0x01 << SPC_VD_IO_CFG_HVDIE_SHIFT) +#define SPC_VD_IO_CFG_HVDIE(x) (((x) << SPC_VD_IO_CFG_HVDIE_SHIFT) & SPC_VD_IO_CFG_HVDIE_MASK) + +#define SPC_VD_IO_CFG_LVSEL_SHIFT (8) +#define SPC_VD_IO_CFG_LVSEL_MASK (0x01 << SPC_VD_IO_CFG_LVSEL_SHIFT) +#define SPC_VD_IO_CFG_LVSEL(x) (((x) << SPC_VD_IO_CFG_LVSEL_SHIFT) & SPC_VD_IO_CFG_LVSEL_MASK) + +#define SPC_VD_IO_CFG_LOCK_SHIFT (16) +#define SPC_VD_IO_CFG_LOCK_MASK (0x01 << SPC_VD_IO_CFG_LOCK_SHIFT) +#define SPC_VD_IO_CFG_LOCK(x) (((x) << SPC_VD_IO_CFG_LOCK_SHIFT) & SPC_VD_IO_CFG_LOCK_MASK) + +/* External Voltage Domain Configuration (EVD_CFG) */ + +#define SPC_EVD_CFG_EVDISO_SHIFT (0) +#define SPC_EVD_CFG_EVDISO_MASK (0x3f << SPC_EVD_CFG_EVDISO_SHIFT) +#define SPC_EVD_CFG_EVDISO(x) (((x) << SPC_EVD_CFG_EVDISO_SHIFT) & SPC_EVD_CFG_EVDISO_MASK) + +#define SPC_EVD_CFG_EVDLPISO_SHIFT (8) +#define SPC_EVD_CFG_EVDLPISO_MASK (0x3f << SPC_EVD_CFG_EVDLPISO_SHIFT) +#define SPC_EVD_CFG_EVDLPISO(x) (((x) << SPC_EVD_CFG_EVDLPISO_SHIFT) & SPC_EVD_CFG_EVDLPISO_MASK) + +#define SPC_EVD_CFG_EVDSTAT_SHIFT (16) +#define SPC_EVD_CFG_EVDSTAT_MASK (0x3f << SPC_EVD_CFG_EVDSTAT_SHIFT) +#define SPC_EVD_CFG_EVDSTAT(x) (((x) << SPC_EVD_CFG_EVDSTAT_SHIFT) & SPC_EVD_CFG_EVDSTAT_MASK) + +/* Glitch Detect Status Control (GLITCH_DETECT_SC) */ + +#define SPC_GLITCH_DETECT_SC_CNT_SELECT_SHIFT (0) +#define SPC_GLITCH_DETECT_SC_CNT_SELECT_MASK (0x03 << SPC_GLITCH_DETECT_SC_CNT_SELECT_SHIFT) +#define SPC_GLITCH_DETECT_SC_CNT_SELECT(x) (((x) << SPC_GLITCH_DETECT_SC_CNT_SELECT_SHIFT) & SPC_GLITCH_DETECT_SC_CNT_SELECT_MASK) + +#define SPC_GLITCH_DETECT_SC_TIMEOUT_SHIFT (2) +#define SPC_GLITCH_DETECT_SC_TIMEOUT_MASK (0x0f << SPC_GLITCH_DETECT_SC_TIMEOUT_SHIFT) +#define SPC_GLITCH_DETECT_SC_TIMEOUT(x) (((x) << SPC_GLITCH_DETECT_SC_TIMEOUT_SHIFT) & SPC_GLITCH_DETECT_SC_TIMEOUT_MASK) + +#define SPC_GLITCH_DETECT_SC_RE_SHIFT (6) +#define SPC_GLITCH_DETECT_SC_RE_MASK (0x01 << SPC_GLITCH_DETECT_SC_RE_SHIFT) +#define SPC_GLITCH_DETECT_SC_RE(x) (((x) << SPC_GLITCH_DETECT_SC_RE_SHIFT) & SPC_GLITCH_DETECT_SC_RE_MASK) + +#define SPC_GLITCH_DETECT_SC_IE_SHIFT (7) +#define SPC_GLITCH_DETECT_SC_IE_MASK (0x01 << SPC_GLITCH_DETECT_SC_IE_SHIFT) +#define SPC_GLITCH_DETECT_SC_IE(x) (((x) << SPC_GLITCH_DETECT_SC_IE_SHIFT) & SPC_GLITCH_DETECT_SC_IE_MASK) + +#define SPC_GLITCH_DETECT_SC_GLITCH_DETECT_FLAG_SHIFT (8) +#define SPC_GLITCH_DETECT_SC_GLITCH_DETECT_FLAG_MASK (0x0f << SPC_GLITCH_DETECT_SC_GLITCH_DETECT_FLAG_SHIFT) +#define SPC_GLITCH_DETECT_SC_GLITCH_DETECT_FLAG(x) (((x) << SPC_GLITCH_DETECT_SC_GLITCH_DETECT_FLAG_SHIFT) & SPC_GLITCH_DETECT_SC_GLITCH_DETECT_FLAG_MASK) + +#define SPC_GLITCH_DETECT_SC_LOCK_SHIFT (16) +#define SPC_GLITCH_DETECT_SC_LOCK_MASK (0x01 << SPC_GLITCH_DETECT_SC_LOCK_SHIFT) +#define SPC_GLITCH_DETECT_SC_LOCK(x) (((x) << SPC_GLITCH_DETECT_SC_LOCK_SHIFT) & SPC_GLITCH_DETECT_SC_LOCK_MASK) + +/* LDO_CORE Configuration (CORELDO_CFG) */ + +#define SPC_CORELDO_CFG_DPDOWN_PULLDOWN_DISABLE_SHIFT (16) +#define SPC_CORELDO_CFG_DPDOWN_PULLDOWN_DISABLE_MASK (0x01) +#define SPC_CORELDO_CFG_DPDOWN_PULLDOWN_DISABLE(x) (((x) << SPC_CORELDO_CFG_DPDOWN_PULLDOWN_DISABLE_SHIFT) & SPC_CORELDO_CFG_DPDOWN_PULLDOWN_DISABLE_MASK) + +/* LDO_SYS Configuration (SYSLDO_CFG) */ + +#define SPC_SYSLDO_CFG_ISINKEN_SHIFT (0) +#define SPC_SYSLDO_CFG_ISINKEN_MASK (0x01 << SPC_SYSLDO_CFG_ISINKEN_SHIFT) +#define SPC_SYSLDO_CFG_ISINKEN(x) (((x) << SPC_SYSLDO_CFG_ISINKEN_SHIFT) & SPC_SYSLDO_CFG_ISINKEN_MASK) + +/* DCDC Configuration (DCDC_CFG) */ + +#define SPC_DCDC_CFG_FREQ_CNTRL_ON_SHIFT (0) +#define SPC_DCDC_CFG_FREQ_CNTRL_ON_MASK (0x01 << SPC_DCDC_CFG_FREQ_CNTRL_ON_SHIFT) +#define SPC_DCDC_CFG_FREQ_CNTRL_ON(x) (((x) << SPC_DCDC_CFG_FREQ_CNTRL_ON_SHIFT) & SPC_DCDC_CFG_FREQ_CNTRL_ON_MASK) + +#define SPC_DCDC_CFG_FREQ_CNTRL_SHIFT (8) +#define SPC_DCDC_CFG_FREQ_CNTRL_MASK (0x3f << SPC_DCDC_CFG_FREQ_CNTRL_SHIFT) +#define SPC_DCDC_CFG_FREQ_CNTRL(x) (((x) << SPC_DCDC_CFG_FREQ_CNTRL_SHIFT) & SPC_DCDC_CFG_FREQ_CNTRL_MASK) + +#define SPC_DCDC_CFG_BLEED_EN_SHIFT (19) +#define SPC_DCDC_CFG_BLEED_EN_MASK (0x01 <> SPC_DCDC_CFG_BLEED_EN_SHIFT) +#define SPC_DCDC_CFG_BLEED_EN(x) (((x) << SPC_DCDC_CFG_BLEED_EN_SHIFT) & SPC_DCDC_CFG_BLEED_EN_MASK) + +/* DCDC Burst Configuration (DCDC_BURST_CFG) */ + +#define SPC_DCDC_BURST_CFG_BURST_REQ_SHIFT (0) +#define SPC_DCDC_BURST_CFG_BURST_REQ_MASK (0x01 << SPC_DCDC_BURST_CFG_BURST_REQ_SHIFT) +#define SPC_DCDC_BURST_CFG_BURST_REQ(x) (((x) << SPC_DCDC_BURST_CFG_BURST_REQ_SHIFT) & SPC_DCDC_BURST_CFG_BURST_REQ_MASK) + +#define SPC_DCDC_BURST_CFG_EXT_BURST_EN_SHIFT (1) +#define SPC_DCDC_BURST_CFG_EXT_BURST_EN_MASK (0x01 << SPC_DCDC_BURST_CFG_EXT_BURST_EN_SHIFT) +#define SPC_DCDC_BURST_CFG_EXT_BURST_EN(x) (((x) << SPC_DCDC_BURST_CFG_EXT_BURST_EN_SHIFT) & SPC_DCDC_BURST_CFG_EXT_BURST_EN_MASK) + +#define SPC_DCDC_BURST_CFG_BURST_ACK_SHIFT (3) +#define SPC_DCDC_BURST_CFG_BURST_ACK_MASK (0x01 << SPC_DCDC_BURST_CFG_BURST_ACK_SHIFT) +#define SPC_DCDC_BURST_CFG_BURST_ACK(x) (((x) << SPC_DCDC_BURST_CFG_BURST_ACK_SHIFT) & SPC_DCDC_BURST_CFG_BURST_ACK_MASK) + +#define SPC_DCDC_BURST_CFG_PULSE_REFRESH_CNT_SHIFT (16) +#define SPC_DCDC_BURST_CFG_PULSE_REFRESH_CNT_MASK (0xffff << SPC_DCDC_BURST_CFG_PULSE_REFRESH_CNT_SHIFT) +#define SPC_DCDC_BURST_CFG_PULSE_REFRESH_CNT(x) (((x) << SPC_DCDC_BURST_CFG_PULSE_REFRESH_CNT_SHIFT) & SPC_DCDC_BURST_CFG_PULSE_REFRESH_CNT_MASK) + +#endif /* ARCH_ARM_SRC_MCX_NXXX_HARDWARE_NXXX_SPC_H */ diff --git a/arch/arm/src/mcx-nxxx/nxxx_clockconfig.c b/arch/arm/src/mcx-nxxx/nxxx_clockconfig.c new file mode 100644 index 0000000000000..5a6c06ed7c79d --- /dev/null +++ b/arch/arm/src/mcx-nxxx/nxxx_clockconfig.c @@ -0,0 +1,438 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/nxxx_clockconfig.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include + +#include "arm_internal.h" +#include "nxxx_clockconfig.h" + +#include "hardware/nxxx_fmu.h" +#include "hardware/nxxx_clock.h" +#include "hardware/nxxx_scg.h" +#include "hardware/nxxx_spc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* The base oscillator frequency is 24MHz */ + +#define XTAL_FREQ 24000000u +#define HFRCO_FREQ 48000000u +#define SYSCLOCK_FREQ 150000000u + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct pll_params_s +{ + uint32_t pllctrl; /* PLL Control */ + uint32_t pllndiv; /* PLL N Divider */ + uint32_t pllpdiv; /* PLL P Divider */ + uint32_t pllmdiv; /* PLL M Divider */ + uint32_t pllsscg[2]; /* PLL Spread Spectrum Control */ + uint32_t pllrate; /* PLL rate */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxxx_sysinit + * + * Description: + * Perform system init for MCX-NXXX. This prepares the SoC for use. + * + * Input Parameters: + * None. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +int nxxx_sysinit(void) +{ + /* Disable ECC to get maximum RAM */ + + putreg32(0, SYSCON_ECC_ENABLE_CTRL); + + /* Enable the flash cache LPCAC */ + + modifyreg32(SYSCON_LPCAC_CTRL, SYSCON_LPCAC_CTRL_DIS_LPCAC_MASK, 0); + + return OK; +} + +/**************************************************************************** + * Name: pll0_setup + * + * Description: + * Setup PLL0 as per given parameters. + * + * Input Parameters: + * params - PLL0 parameters. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +int pll0_setup(struct pll_params_s *params) +{ + uint32_t inclk; + uint32_t outclk; + uint32_t prediv; + uint32_t cnfg; + uint32_t clksrc; + + /* Enable LDO */ + + modifyreg32(NXXX_CFG_LDOCSR, 0, SCG_LDOCSR_LDOEN); + + /* Shut down PLL0 when we are configuring it */ + + modifyreg32(NXXX_SCG_APLLCSR, + SCG_APLLCSR_APLLPWREN_MASK | SCG_APLLCSR_APLLCLKEN_MASK, + 0); + + /* Configure PLL as per given parameters */ + + putreg32(params->pllctrl, NXXX_SCG_APLLCTRL); + putreg32(params->pllndiv, NXXX_SCG_APLLNDIV); + putreg32(params->pllndiv | SCG_APLLNDIV_NREQ_MASK, NXXX_SCG_APLLNDIV); + putreg32(params->pllpdiv, NXXX_SCG_APLLPDIV); + putreg32(params->pllpdiv | SCG_APLLPDIV_PREQ_MASK, NXXX_SCG_APLLPDIV); + putreg32(params->pllmdiv, NXXX_SCG_APLLMDIV); + putreg32(params->pllmdiv | SCG_APLLMDIV_MREQ_MASK, NXXX_SCG_APLLMDIV); + putreg32(params->pllsscg[0], NXXX_SCG_APLLSSCG0); + putreg32(params->pllsscg[1], NXXX_SCG_APLLSSCG1); + + /* Unlock APLLLOCK_CNFG register */ + + putreg32(0x5a5a0001, NXXX_SCG_TRIM_LOCK); + + /* Configure lock time for APLL */ + + clksrc = getreg32(NXXX_SCG_APLLCTRL); + clksrc = clksrc & SCG_APLLCTRL_SOURCE_MASK >> SCG_APLLCTRL_SOURCE_SHIFT; + + switch (clksrc) + { + case 0: + inclk = XTAL_FREQ; + break; + + case 1: + inclk = HFRCO_FREQ; + break; + + default: + return -EINVAL; + } + + if ((getreg32(NXXX_SCG_APLLCTRL) & SCG_APLLCTRL_BYPASSPREDIV_MASK) == 0) + { + prediv = getreg32(NXXX_SCG_APLLNDIV) & SCG_APLLNDIV_NDIV_MASK; + if (prediv == 0) + { + prediv = 1; + } + } + + /* Adjust input clock */ + + outclk = inclk / prediv; + cnfg = SCG_APLLLOCK_CNFG_LOCK_TIME(outclk / 2000 + 300); + + putreg32(cnfg, NXXX_SCG_APLLLOCK_CNFG); + + /* Power on PLL0 and enable PLL0 clock */ + + modifyreg32(NXXX_SCG_APLLCSR, + 0, + SCG_APLLCSR_APLLPWREN_MASK | SCG_APLLCSR_APLLCLKEN_MASK); + + /* Wait for APLL lock */ + + while ((getreg32(NXXX_SCG_APLLCSR) & SCG_APLLCSR_APLL_LOCK_MASK) != 0) + { + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxxx_clockconfig + * + * Description: + * Called to initialize the clocks for MCX-NXXX. This does whatever setup + * is needed to put the SoC in a usable state. This includes the + * initialization of clocking using the settings in board.h. + * + ****************************************************************************/ + +void nxxx_clockconfig(void) +{ + /* Prepare the SoC for use */ + + nxxx_sysinit(); + + /* This sets up the system clock at 150MHz */ + + nxxx_set_clock_gate(CLOCK_GATE_SCG, true); + + /* Do the clock configuration with the 12MHz FRO main clock */ + + putreg32(SCG_RCCR_SCS_SIRC, NXXX_SCG_RCCR); + + while ((getreg32(NXXX_SCG_CSR) & SCG_CSR_SCS_MASK) != SCG_RCCR_SCS_SIRC) + { + } + + /* Set the DCDC VDD regulator to 1.2 V voltage level */ + + modifyreg32(NXXX_SPC_ACTIVE_CFG, + SPC_ACTIVE_CFG_DCDC_VDD_DS_MASK, + SPC_ACTIVE_CFG_DCDC_VDD_DS(SPC_DCDC_NORMALDRIVESTRENGTH)); + modifyreg32(NXXX_SPC_ACTIVE_CFG, + SPC_ACTIVE_CFG_DCDC_VDD_LVL_MASK, + SPC_ACTIVE_CFG_DCDC_VDD_LVL(SPC_DCDC_OVERDRIVEVOLTAGE)); + + while ((getreg32(NXXX_SPC_SC) & SPC_SC_BUSY_MASK) != 0) + { + } + + /* Set the LDO_CORE VDD regulator to 1.2 V voltage level */ + + modifyreg32(NXXX_SPC_ACTIVE_CFG, + SPC_ACTIVE_CFG_CORELDO_VDD_DS_MASK, + SPC_ACTIVE_CFG_CORELDO_VDD_DS( + SPC_CORELDO_NORMALDRIVESTRENGTH)); + modifyreg32(NXXX_SPC_ACTIVE_CFG, + SPC_ACTIVE_CFG_CORELDO_VDD_LVL_MASK, + SPC_ACTIVE_CFG_CORELDO_VDD_LVL(SPC_CORELDO_OVERDRIVEVOLTAGE)); + + while ((getreg32(NXXX_SPC_SC) & SPC_SC_BUSY_MASK) != 0) + { + } + + /* Configure Flash wait-states for 150MHz */ + + modifyreg32(NXXX_FMU_FCTRL, FMU_FCTRL_RWSC_MASK, FMU_FCTRL_RWSC(3)); + + /* Set 1.2V SRAM voltage */ + + putreg32(SPC_SRAMCTL_VSM(SPC_SRAM1V2), NXXX_SPC_SRAMCTL); + + /* Request for voltage update */ + + modifyreg32(NXXX_SPC_SRAMCTL, 0, SPC_SRAMCTL_REQ_MASK); + + while ((getreg32(NXXX_SPC_SRAMCTL) & SPC_SRAMCTL_ACK_MASK) == 0) + { + } + + modifyreg32(NXXX_SPC_SRAMCTL, SPC_SRAMCTL_REQ_MASK, 0); + + /* Select 48MHz for FIRC clock */ + + putreg32(SCG_FIRCCFG_48MHZ, NXXX_SCG_FIRCCFG); + + /* Unlock FIRCCSR */ + + modifyreg32(NXXX_SCG_FIRCCSR, SCG_FIRCCSR_LK, 0); + + /* Enable FIRC 48 MHz clock for peripheral use */ + + modifyreg32(NXXX_SCG_FIRCCSR, 0, SCG_FIRCCSR_SCLK_PERIPH_EN); + + /* Enable FIRC 144 MHz clock for peripheral use */ + + modifyreg32(NXXX_SCG_FIRCCSR, 0, SCG_FIRCCSR_FCLK_PERIPH_EN); + + /* Enable FIRC */ + + modifyreg32(NXXX_SCG_FIRCCSR, 0, SCG_FIRCCSR_FIRCEN); + + /* Wait for FIRC clock to be valid. */ + + while ((getreg32(NXXX_SCG_FIRCCSR) & SCG_FIRCCSR_FIRCVLD) == 0) + { + } + + /* Setup PLL0 for 150MHz */ + + struct pll_params_s pll0_params = + { + .pllctrl = SCG_APLLCTRL_SOURCE(1) | + SCG_APLLCTRL_SELI(27) | + SCG_APLLCTRL_SELP(13), + .pllndiv = SCG_APLLNDIV_NDIV(8), + .pllpdiv = SCG_APLLPDIV_PDIV(1), + .pllmdiv = SCG_APLLMDIV_MDIV(50), + .pllrate = SYSCLOCK_FREQ + }; + + pll0_setup(&pll0_params); + + /* Disable Pll0 monitor */ + + modifyreg32(NXXX_SCG_APLLCSR, + SCG_APLLCSR_APLLCM_MASK | SCG_APLLCSR_APLLCMRE_MASK, + 0); + + /* Take the PLL0 clock into use */ + + modifyreg32(SYSCON_DIVAHBCLK, 0, SYSCON_CLKDIV_RESET | SYSCON_CLKDIV_HALT); + putreg32(0, SYSCON_DIVAHBCLK); + putreg32(SCG_RCCR_SCS_APLL, NXXX_SCG_RCCR); + + while ((getreg32(NXXX_SCG_CSR) & SCG_CSR_SCS_MASK) != SCG_RCCR_SCS_APLL) + { + } + + /* Enable PORT clocks, otherwise pin configuration will not work */ + + nxxx_set_clock_gate(CLOCK_GATE_PORT0, true); + nxxx_set_clock_gate(CLOCK_GATE_PORT1, true); + nxxx_set_clock_gate(CLOCK_GATE_PORT2, true); + nxxx_set_clock_gate(CLOCK_GATE_PORT3, true); + nxxx_set_clock_gate(CLOCK_GATE_PORT4, true); +} + +/**************************************************************************** + * Name: nxxx_set_periphclock + * + * Description: + * This function sets the clock frequency of the specified peripheral + * functional clock. + * + * Input Parameters: + * clock - Identifies the peripheral clock of interest + * sel - Selected clock source (every peripheral has its own set of + * possible sources) + * div - Divider for the clock + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. -ENODEV is returned if the clock is not enabled or is not + * being clocked. + * + ****************************************************************************/ + +int nxxx_set_periphclock(struct clock_regs_s clock, uint32_t sel, + uint32_t div) +{ + /* First, halt the clock divider */ + + modifyreg32(clock.div, 0, SYSCON_CLKDIV_RESET | SYSCON_CLKDIV_HALT); + + /* Then set the divider, divider of 0 means to halt the clock */ + + if (div > 0) + { + putreg32(div - 1, clock.div); + } + + /* Then apply the clock selector */ + + putreg32(sel, clock.mux); + + return OK; +} + +/**************************************************************************** + * Name: nxxx_set_clock_gate + * + * Description: + * Open or close a specific clock gate. + * + * Input Parameters: + * gate - Identifies the peripheral clock gate of interest. + * enabled - True enables the clock; false disables it. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. -ENODEV is returned if the clock is not enabled or is not + * being clocked. + * + ****************************************************************************/ + +int nxxx_set_clock_gate(struct clock_gate_reg_s gate, bool enabled) +{ + /* Note: we use true to enable the clock, not the clock gate. This might + * be confusing to some, but the API is more intuitive when true enables + * the clock. + */ + + if (enabled) + { + putreg32(1 << gate.bit, AHB_CLK_CTRL_SET0 + (gate.reg & 0xf)); + } + else + { + putreg32(1 << gate.bit, AHB_CLK_CTRL_CLR0 + (gate.reg & 0xf)); + } + + return OK; +} + +/**************************************************************************** + * Name: nxxx_get_coreclk + * + * Description: + * Return the current value of the CORE clock frequency. + * + * Input Parameters: + * None + * + * Returned Values: + * The current value of the CORE clock frequency. Zero is returned on any + * failure. + * + ****************************************************************************/ + +uint32_t nxxx_get_coreclk(void) +{ + return SYSCLOCK_FREQ; +} diff --git a/arch/arm/src/mcx-nxxx/nxxx_clockconfig.h b/arch/arm/src/mcx-nxxx/nxxx_clockconfig.h new file mode 100644 index 0000000000000..7a27edeae13c0 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/nxxx_clockconfig.h @@ -0,0 +1,118 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/nxxx_clockconfig.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_MCX_NXXX_NXXX_CLOCKCONFIG_H +#define __ARCH_ARM_SRC_MCX_NXXX_NXXX_CLOCKCONFIG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "hardware/nxxx_clock.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nxxx_clockconfig + * + * Description: + * Called to initialize the clocks for MCX-NXXX. This does whatever setup + * is needed to put the SoC in a usable state. This includes the + * initialization of clocking using the settings in board.h. + * + ****************************************************************************/ + +void nxxx_clockconfig(void); + +/**************************************************************************** + * Name: nxxx_set_periphclock + * + * Description: + * This function sets the clock frequency of the specified peripheral + * functional clock. + * + * Input Parameters: + * clock - Identifies the peripheral clock of interest + * sel - Selected clock source (every peripheral has its own set of + * possible sources) + * div - Divider for the clock + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. -ENODEV is returned if the clock is not enabled or is not + * being clocked. + * + ****************************************************************************/ + +int nxxx_set_periphclock(struct clock_regs_s clock, uint32_t sel, + uint32_t div); + +/**************************************************************************** + * Name: nxxx_set_clock_gate + * + * Description: + * Open or close a specific clock gate. + * + * Input Parameters: + * gate - Identifies the peripheral clock gate of interest. + * enabled - True enables the clock; false disables it. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. -ENODEV is returned if the clock is not enabled or is not + * being clocked. + * + ****************************************************************************/ + +int nxxx_set_clock_gate(struct clock_gate_reg_s gate, bool enabled); + +/**************************************************************************** + * Name: nxxx_get_coreclk + * + * Description: + * Return the current value of the CORE clock frequency. + * + * Input Parameters: + * None + * + * Returned Values: + * The current value of the CORE clock frequency. Zero is returned on any + * failure. + * + ****************************************************************************/ + +uint32_t nxxx_get_coreclk(void); + +#endif /* __ARCH_ARM_SRC_MCX_NXXX_NXXX_CLOCKCONFIG_H */ diff --git a/arch/arm/src/mcx-nxxx/nxxx_gpio.c b/arch/arm/src/mcx-nxxx/nxxx_gpio.c new file mode 100644 index 0000000000000..2862e0b7ed0b9 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/nxxx_gpio.c @@ -0,0 +1,279 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/nxxx_gpio.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "nxxx_gpio.h" + +#include + +#include +#include +#include +#include +#include + +#include + +#include "chip.h" +#include "nxxx_gpiobase.c" +#include "arm_internal.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxxx_gpio_dirout + ****************************************************************************/ + +static inline void nxxx_gpio_dirout(uint32_t port, uint32_t pin) +{ + uint32_t regval = getreg32(NXXX_GPIO_PDDR(port)); + regval |= GPIO_PIN(pin); + putreg32(regval, NXXX_GPIO_PDDR(port)); +} + +/**************************************************************************** + * Name: nxxx_gpio_dirin + ****************************************************************************/ + +static inline void nxxx_gpio_dirin(uint32_t port, uint32_t pin) +{ + uint32_t regval = getreg32(NXXX_GPIO_PDDR(port)); + regval &= ~GPIO_PIN(pin); + putreg32(regval, NXXX_GPIO_PDDR(port)); +} + +/**************************************************************************** + * Name: nxxx_gpio_setoutput + ****************************************************************************/ + +static void nxxx_gpio_setoutput(uint32_t port, uint32_t pin, bool value) +{ + uintptr_t regaddr = NXXX_GPIO_PDOR(port); + uint32_t regval; + + regval = getreg32(regaddr); + if (value) + { + regval |= GPIO_PIN(pin); + } + else + { + regval &= ~GPIO_PIN(pin); + } + + putreg32(regval, regaddr); +} + +/**************************************************************************** + * Name: nxxx_gpio_getpin_status + ****************************************************************************/ + +static inline bool nxxx_gpio_get_pinstatus(uint32_t port, uint32_t pin) +{ + uintptr_t regaddr = NXXX_GPIO_PSOR(port); + uint32_t regval; + + regval = getreg32(regaddr); + return ((regval & GPIO_PIN(pin)) != 0); +} + +/**************************************************************************** + * Name: nxxx_gpio_getinput + ****************************************************************************/ + +static inline bool nxxx_gpio_getinput(uint32_t port, uint32_t pin) +{ + uintptr_t regaddr = NXXX_GPIO_PDIR(port); + uint32_t regval; + + regval = getreg32(regaddr); + return ((regval & GPIO_PIN(pin)) != 0); +} + +/**************************************************************************** + * Name: nxxx_gpio_configinput + ****************************************************************************/ + +static int nxxx_gpio_configinput(gpio_pinset_t pinset) +{ + uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + + DEBUGASSERT((unsigned int)port < NXXX_GPIO_NPORTS); + + /* Configure pin as in input */ + + nxxx_gpio_dirin(port, pin); + + return OK; +} + +/**************************************************************************** + * Name: nxxx_gpio_configoutput + ****************************************************************************/ + +static inline int nxxx_gpio_configoutput(gpio_pinset_t pinset) +{ + uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + bool value = ((pinset & GPIO_OUTPUT_ONE) != 0); + + DEBUGASSERT((unsigned int)port < NXXX_GPIO_NPORTS); + + /* Set the output value */ + + nxxx_gpio_setoutput(port, pin, value); + + /* Convert the configured input GPIO to an output */ + + nxxx_gpio_dirout(port, pin); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxxx_config_gpio + * + * Description: + * Configure a GPIO pin based on pin-encoded description of the pin. + * + ****************************************************************************/ + +int nxxx_config_gpio(gpio_pinset_t pinset) +{ + irqstate_t flags; + int ret; + + /* Configure the pin as an input initially to avoid any spurious outputs */ + + flags = enter_critical_section(); + + /* Configure based upon the pin mode */ + + switch (pinset & GPIO_MODE_MASK) + { + case GPIO_INPUT: + { + /* Configure the pin as a GPIO input */ + + ret = nxxx_gpio_configinput(pinset); + } + break; + + case GPIO_OUTPUT: + { + /* First configure the pin as a GPIO input to avoid output + * glitches. + */ + + ret = nxxx_gpio_configinput(pinset); + if (ret >= 0) + { + /* Convert the input to an output */ + + ret = nxxx_gpio_configoutput(pinset); + } + } + break; + +#ifdef CONFIG_NXXX_GPIO_IRQ + case GPIO_INTERRUPT: + { + /* Configure the pin as a GPIO input */ + + ret = nxxx_gpio_configinput(pinset); + if (ret == OK) + { + ret = nxxx_gpioirq_configure(pinset); + } + } + break; +#endif + + default: + ret = -EINVAL; + break; + } + + leave_critical_section(flags); + return ret; +} + +/**************************************************************************** + * Name: nxxx_gpio_write + * + * Description: + * Write one or zero to the selected GPIO pin + * + ****************************************************************************/ + +void nxxx_gpio_write(gpio_pinset_t pinset, bool value) +{ + irqstate_t flags; + uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + + DEBUGASSERT((unsigned int)port < NXXX_GPIO_NPORTS); + + flags = enter_critical_section(); + nxxx_gpio_setoutput(port, pin, value); + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: nxxx_gpio_read + * + * Description: + * Read one or zero from the selected GPIO pin + * + ****************************************************************************/ + +bool nxxx_gpio_read(gpio_pinset_t pinset) +{ + irqstate_t flags; + uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + bool value; + + DEBUGASSERT((unsigned int)port < NXXX_GPIO_NPORTS); + + flags = enter_critical_section(); + if ((pinset & (GPIO_OUTPUT)) == (GPIO_OUTPUT)) + { + value = nxxx_gpio_get_pinstatus(port, pin); + } + else + { + value = nxxx_gpio_getinput(port, pin); + } + + leave_critical_section(flags); + return value; +} diff --git a/arch/arm/src/mcx-nxxx/nxxx_gpio.h b/arch/arm/src/mcx-nxxx/nxxx_gpio.h new file mode 100644 index 0000000000000..c938dece9b1fa --- /dev/null +++ b/arch/arm/src/mcx-nxxx/nxxx_gpio.h @@ -0,0 +1,340 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/nxxx_gpio.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_MCX_NXXX_NXXX_GPIO_H +#define __ARCH_ARM_SRC_MCX_NXXX_NXXX_GPIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "hardware/nxxx_gpio.h" + +#include + +#include +#include + +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* GPIO pinset is a 16-bit word used to configure the GPIO settings. + * The encoding is as follows... + * + * 1111 1100 0000 0000 + * 5432 1098 7654 3210 + * ENCODING MMVX BEEG GGGP PPPP + * GPIO INPUT 00.. BEEG GGGP PPPP + * INT INPUT 11.. BEEG GGGP PPPP + * GPIO OUTPUT 01V. ...G GGGP PPPP + */ + +/* Input/Output Selection: + * + * 1111 1100 0000 0000 + * 5432 1098 7654 3210 + * ENCODING MM.. .... .... .... + */ + +#define GPIO_MODE_SHIFT (14) /* Bits 14-15: Pin mode */ +#define GPIO_MODE_MASK (0x3 << GPIO_MODE_SHIFT) +# define GPIO_INPUT (0 << GPIO_MODE_SHIFT) /* GPIO input */ +# define GPIO_OUTPUT (1 << GPIO_MODE_SHIFT) /* GPIO output */ +# define GPIO_INTERRUPT (2 << GPIO_MODE_SHIFT) /* Interrupt input */ + +/* Initial Output Value: + * + * 1111 1100 0000 0000 + * 5432 1098 7654 3210 + * GPIO OUTPUT 01V. .... .... .... + */ + +#define GPIO_OUTPUT_SHIFT (13) /* Bit 13: Initial output */ +#define GPIO_OUTPUT_MASK (0x1 << GPIO_OUTPUT_SHIFT) +# define GPIO_OUTPUT_ZERO (0 << GPIO_OUTPUT_SHIFT) /* Bit 29: 0=Initial output is low */ +# define GPIO_OUTPUT_ONE (1 << GPIO_OUTPUT_SHIFT) /* Bit 29: 1=Initial output is high */ + +/* Interrupt on both edges configuration + * + * 1111 1100 0000 0000 + * 5432 1098 7654 3210 + * INT INPUT 11.. B... .... .... + */ + +#define GPIO_INTBOTHCFG_SHIFT (11) /* Bit 11: Interrupt both edges configuration */ +#define GPIO_INTBOTHCFG_MASK (1 << GPIO_INTBOTHCFG_SHIFT) +# define GPIO_INTBOTH_EDGES (1 << GPIO_INTBOTHCFG_SHIFT) + +/* Interrupt edge/level configuration + * + * 1111 1100 0000 0000 + * 5432 1098 7654 3210 + * INT INPUT 11.. .EE. .... .... + */ + +#define GPIO_INTCFG_SHIFT (9) /* Bits 9-10: Interrupt edge/level configuration */ +#define GPIO_INTCFG_MASK (0x3 << GPIO_INTCFG_SHIFT) +# define GPIO_INT_LOWLEVEL (0 << GPIO_INTCFG_SHIFT) +# define GPIO_INT_HIGHLEVEL (1 << GPIO_INTCFG_SHIFT) +# define GPIO_INT_RISINGEDGE (2 << GPIO_INTCFG_SHIFT) +# define GPIO_INT_FALLINGEDGE (3 << GPIO_INTCFG_SHIFT) + +/* GPIO Port Number + * + * 1111 1100 0000 0000 + * 5432 1098 7654 3210 + * GPIO IN/OUT .... ...G GGG. .... + */ + +#define GPIO_PORT_SHIFT (5) /* Bits 5-8: GPIO port index */ +#define GPIO_PORT_MASK (0xf << GPIO_PORT_SHIFT) +# define GPIO_PORT1 (GPIO1 << GPIO_PORT_SHIFT) /* GPIO1 */ +# define GPIO_PORT2 (GPIO2 << GPIO_PORT_SHIFT) /* GPIO2 */ +# define GPIO_PORT3 (GPIO3 << GPIO_PORT_SHIFT) /* GPIO3 */ +# define GPIO_PORT4 (GPIO4 << GPIO_PORT_SHIFT) /* GPIO4 */ +# define GPIO_PORT5 (GPIO5 << GPIO_PORT_SHIFT) /* GPIO5 */ +# define GPIO_PORT6 (GPIO6 << GPIO_PORT_SHIFT) /* GPIO6 */ +# define GPIO_PORT7 (GPIO7 << GPIO_PORT_SHIFT) /* GPIO7 */ +# define GPIO_PORT8 (GPIO8 << GPIO_PORT_SHIFT) /* GPIO8 */ +# define GPIO_PORT9 (GPIO9 << GPIO_PORT_SHIFT) /* GPIO9 */ +# define GPIO_PORT10 (GPIO10 << GPIO_PORT_SHIFT) /* GPIO10 */ +# define GPIO_PORT11 (GPIO11 << GPIO_PORT_SHIFT) /* GPIO11 */ +# define GPIO_PORT12 (GPIO12 << GPIO_PORT_SHIFT) /* GPIO12 */ +# define GPIO_PORT13 (GPIO13 << GPIO_PORT_SHIFT) /* GPIO13 */ + +/* GPIO Pin Number: + * + * 1111 1100 0000 0000 + * 5432 1098 7654 3210 + * GPIO IN/OUT .... .... ...P PPPP + */ + +#define GPIO_PIN_SHIFT (0) /* Bits 0-4: GPIO pin number */ +#define GPIO_PIN_MASK (0x1f << GPIO_PIN_SHIFT) +# define GPIO_PIN0 (0 << GPIO_PIN_SHIFT) /* Pin 0 */ +# define GPIO_PIN1 (1 << GPIO_PIN_SHIFT) /* Pin 1 */ +# define GPIO_PIN2 (2 << GPIO_PIN_SHIFT) /* Pin 2 */ +# define GPIO_PIN3 (3 << GPIO_PIN_SHIFT) /* Pin 3 */ +# define GPIO_PIN4 (4 << GPIO_PIN_SHIFT) /* Pin 4 */ +# define GPIO_PIN5 (5 << GPIO_PIN_SHIFT) /* Pin 5 */ +# define GPIO_PIN6 (6 << GPIO_PIN_SHIFT) /* Pin 6 */ +# define GPIO_PIN7 (7 << GPIO_PIN_SHIFT) /* Pin 7 */ +# define GPIO_PIN8 (8 << GPIO_PIN_SHIFT) /* Pin 8 */ +# define GPIO_PIN9 (9 << GPIO_PIN_SHIFT) /* Pin 9 */ +# define GPIO_PIN10 (10 << GPIO_PIN_SHIFT) /* Pin 10 */ +# define GPIO_PIN11 (11 << GPIO_PIN_SHIFT) /* Pin 11 */ +# define GPIO_PIN12 (12 << GPIO_PIN_SHIFT) /* Pin 12 */ +# define GPIO_PIN13 (13 << GPIO_PIN_SHIFT) /* Pin 13 */ +# define GPIO_PIN14 (14 << GPIO_PIN_SHIFT) /* Pin 14 */ +# define GPIO_PIN15 (15 << GPIO_PIN_SHIFT) /* Pin 15 */ +# define GPIO_PIN16 (16 << GPIO_PIN_SHIFT) /* Pin 16 */ +# define GPIO_PIN17 (17 << GPIO_PIN_SHIFT) /* Pin 17 */ +# define GPIO_PIN18 (18 << GPIO_PIN_SHIFT) /* Pin 18 */ +# define GPIO_PIN19 (19 << GPIO_PIN_SHIFT) /* Pin 19 */ +# define GPIO_PIN20 (20 << GPIO_PIN_SHIFT) /* Pin 20 */ +# define GPIO_PIN21 (21 << GPIO_PIN_SHIFT) /* Pin 21 */ +# define GPIO_PIN22 (22 << GPIO_PIN_SHIFT) /* Pin 22 */ +# define GPIO_PIN23 (23 << GPIO_PIN_SHIFT) /* Pin 23 */ +# define GPIO_PIN24 (24 << GPIO_PIN_SHIFT) /* Pin 24 */ +# define GPIO_PIN25 (25 << GPIO_PIN_SHIFT) /* Pin 25 */ +# define GPIO_PIN26 (26 << GPIO_PIN_SHIFT) /* Pin 26 */ +# define GPIO_PIN27 (27 << GPIO_PIN_SHIFT) /* Pin 27 */ +# define GPIO_PIN28 (28 << GPIO_PIN_SHIFT) /* Pin 28 */ +# define GPIO_PIN29 (29 << GPIO_PIN_SHIFT) /* Pin 29 */ +# define GPIO_PIN30 (30 << GPIO_PIN_SHIFT) /* Pin 30 */ +# define GPIO_PIN31 (31 << GPIO_PIN_SHIFT) /* Pin 31 */ + +/* Port access via global LUT */ + +#define NXXX_GPIO_BASE(n) g_gpio_base[n] /* Use GPIO1..GPIOn macros as indices */ + +#define NXXX_GPIO_VERID(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_VERID_OFFSET) +#define NXXX_GPIO_PARAM(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_PARAM_OFFSET) +#define NXXX_GPIO_LOCK(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_LOCK_OFFSET) +#define NXXX_GPIO_PCNS(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_PCNS_OFFSET) +#define NXXX_GPIO_ICNS(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_ICNS_OFFSET) +#define NXXX_GPIO_PCNP(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_PCNP_OFFSET) +#define NXXX_GPIO_ICNP(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_ICNP_OFFSET) +#define NXXX_GPIO_PDOR(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_PDOR_OFFSET) +#define NXXX_GPIO_PSOR(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_PSOR_OFFSET) +#define NXXX_GPIO_PCOR(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_PCOR_OFFSET) +#define NXXX_GPIO_PTOR(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_PTOR_OFFSET) +#define NXXX_GPIO_PDIR(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_PDIR_OFFSET) +#define NXXX_GPIO_PDDR(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_PDDR_OFFSET) +#define NXXX_GPIO_PIDR(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_PIDR_OFFSET) +#define NXXX_GPIO_GICLR(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_GICLR_OFFSET) +#define NXXX_GPIO_GICHR(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_GICHR_OFFSET) + +/* Interrupt status flags, these have two channels. Channel is selected by + * setting / clearing ICRN.IRQS bit. + */ + +#define NXXX_GPIO_ISFR0(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_ISFR0_OFFSET) +#define NXXX_GPIO_ISFR1(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_ISFR1_OFFSET) + +/* GPIO PIN[0...31] and ICR[0...31] */ + +#define NXXX_GPIO_P0DR(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_P0DR_OFFSET) +#define NXXX_GPIO_PNDR(n, p) (NXXX_GPIO_P0DR(n) + ((p) * 0x4)) +#define NXXX_GPIO_ICR0(n) (NXXX_GPIO_BASE(n) + NXXX_GPIO_ICR0_OFFSET) +#define NXXX_GPIO_ICRN(n, p) (NXXX_GPIO_ICR0(n) + ((p) * 0x4)) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* The smallest integer type that can hold the GPIO encoding */ + +typedef uint16_t gpio_pinset_t; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/* Look-up table that maps GPIO1..GPIOn indexes into GPIO register base + * addresses + */ + +EXTERN const uintptr_t g_gpio_base[]; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nxxx_gpioirq_initialize + * + * Description: + * Initialize logic to support a second level of interrupt decoding for + * GPIO pins. + * + ****************************************************************************/ + +#ifdef CONFIG_NXXX_GPIO_IRQ +void nxxx_gpioirq_initialize(void); +#else +# define nxxx_gpioirq_initialize() +#endif + +/**************************************************************************** + * Name: nxxx_config_gpio + * + * Description: + * Configure a GPIO pin based on bit-encoded description of the pin. + * + ****************************************************************************/ + +int nxxx_config_gpio(gpio_pinset_t pinset); + +/**************************************************************************** + * Name: nxxx_gpio_write + * + * Description: + * Write one or zero to the selected GPIO pin + * + ****************************************************************************/ + +void nxxx_gpio_write(gpio_pinset_t pinset, bool value); + +/**************************************************************************** + * Name: nxxx_gpio_read + * + * Description: + * Read one or zero from the selected GPIO pin + * + ****************************************************************************/ + +bool nxxx_gpio_read(gpio_pinset_t pinset); + +/**************************************************************************** + * Name: nxxx_gpioirq_attach + * + * Description: + * Attach a pin interrupt handler. + * + ****************************************************************************/ + +#ifdef CONFIG_NXXX_GPIO_IRQ +int nxxx_gpioirq_attach(gpio_pinset_t pinset, xcpt_t isr, void *arg); +#else +#define nxxx_gpioirq_attach(pinset, isr, arg) 0 +#endif + +/**************************************************************************** + * Name: nxxx_gpioirq_configure + * + * Description: + * Configure an interrupt for the specified GPIO pin. + * + ****************************************************************************/ + +#ifdef CONFIG_NXXX_GPIO_IRQ +int nxxx_gpioirq_configure(gpio_pinset_t pinset); +#else +# define nxxx_gpioirq_configure(pinset) 0 +#endif + +/**************************************************************************** + * Name: nxxx_gpioirq_enable + * + * Description: + * Enable the interrupt for specified GPIO IRQ + * + ****************************************************************************/ + +#ifdef CONFIG_NXXX_GPIO_IRQ +int nxxx_gpioirq_enable(gpio_pinset_t pinset); +#else +# define nxxx_gpioirq_enable(pinset) 0 +#endif + +/**************************************************************************** + * Name: nxxx_gpioirq_disable + * + * Description: + * Disable the interrupt for specified GPIO IRQ + * + ****************************************************************************/ + +#ifdef CONFIG_NXXX_GPIO_IRQ +int nxxx_gpioirq_disable(gpio_pinset_t pinset); +#else +# define nxxx_gpioirq_disable(pinset) 0 +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ARCH_ARM_SRC_MCX_NXXX_NXXX_GPIO_H */ diff --git a/arch/arm/src/mcx-nxxx/nxxx_gpiobase.c b/arch/arm/src/mcx-nxxx/nxxx_gpiobase.c new file mode 100644 index 0000000000000..cbccb381c59de --- /dev/null +++ b/arch/arm/src/mcx-nxxx/nxxx_gpiobase.c @@ -0,0 +1,53 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/nxxx_gpiobase.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "nxxx_gpio.h" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#if defined(CONFIG_ARCH_CHIP_N236) +/* Base address for the GPIO memory mapped registers */ + +const uintptr_t g_gpio_base[] = +{ + NXXX_GPIO0_BASE, + NXXX_GPIO1_BASE, + NXXX_GPIO2_BASE, + NXXX_GPIO3_BASE, + NXXX_GPIO4_BASE, + NXXX_GPIO5_BASE, +}; +#else +# error Unrecognized NXXx architecture +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ diff --git a/arch/arm/src/mcx-nxxx/nxxx_gpioirq.c b/arch/arm/src/mcx-nxxx/nxxx_gpioirq.c new file mode 100644 index 0000000000000..3724913709ef8 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/nxxx_gpioirq.c @@ -0,0 +1,316 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/nxxx_gpioirq.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "nxxx_gpio.h" +#include "arm_internal.h" + +#ifdef CONFIG_NXXX_GPIO_IRQ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct nxxx_portisr_s +{ + struct + { + xcpt_t isr; /* The interrupt service routine */ + void *arg; /* Argument passed to it */ + } + pins[NXXX_GPIO_NPINS]; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct nxxx_portisr_s g_isrtab[NXXX_GPIO_NPORTS]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxxx_gpio_interrupt + * + * Description: + * GPIO interrupt handlers. NXXx has two interrupt sources for each pin, + * the NuttX driver uses source 0. + * + ****************************************************************************/ + +static int nxxx_gpio_interrupt(int irq, void *context, void *arg) +{ + uint32_t port = (uint32_t)((uintptr_t)arg) >> GPIO_PORT_SHIFT; + uint32_t status; + uint32_t pin; + uint32_t regaddr; + + /* Get the pending interrupt indications */ + + regaddr = NXXX_GPIO_ISFR0(port); + status = getreg32(regaddr); + + /* Decode the pending interrupts */ + + for (pin = 0; pin < 32 && status != 0; pin++) + { + /* Is the IRQ associated with this pin pending? */ + + uint32_t mask = (1 << pin); + if ((status & mask) != 0) + { + struct nxxx_portisr_s *isrtab; + + /* Yes, clear the status bit and dispatch the interrupt */ + + putreg32(mask, regaddr); + status &= ~mask; + + /* Get the interrupt table for this port */ + + isrtab = &g_isrtab[port]; + if (isrtab->pins[pin].isr != NULL) + { + /* Run the user handler with the user's argument */ + + isrtab->pins[pin].isr(irq, context, isrtab->pins[pin].arg); + } + } + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxxx_gpioirq_initialize + * + * Description: + * Initialize logic to support a second level of interrupt decoding for + * GPIO pins. + * + ****************************************************************************/ + +void nxxx_gpioirq_initialize(void) +{ + uint32_t port; + uint32_t pin; + + /* Disable all GPIO interrupts at the source */ + + for (port = 0; port < NXXX_GPIO_NPORTS; port++) + { + for (pin = 0; pin < NXXX_GPIO_NPINS; pin++) + { + /* Reset the interrupt configuration, disabling the interrupt */ + + putreg32(0, NXXX_GPIO_ICRN(port, pin)); + } + } + + /* Disable all GPIO interrupts */ + + up_disable_irq(NXXX_IRQ_GPIO00); + up_disable_irq(NXXX_IRQ_GPIO01); + + up_disable_irq(NXXX_IRQ_GPIO10); + up_disable_irq(NXXX_IRQ_GPIO11); + + up_disable_irq(NXXX_IRQ_GPIO20); + up_disable_irq(NXXX_IRQ_GPIO21); + + up_disable_irq(NXXX_IRQ_GPIO30); + up_disable_irq(NXXX_IRQ_GPIO31); + + up_disable_irq(NXXX_IRQ_GPIO40); + up_disable_irq(NXXX_IRQ_GPIO41); + + up_disable_irq(NXXX_IRQ_GPIO50); + up_disable_irq(NXXX_IRQ_GPIO51); + + /* Attach the common GPIO interrupt handler and enable the interrupt */ + + DEBUGVERIFY(irq_attach(NXXX_IRQ_GPIO00, + nxxx_gpio_interrupt, (void *)GPIO_PORT0)); + up_enable_irq(NXXX_IRQ_GPIO00); + + DEBUGVERIFY(irq_attach(NXXX_IRQ_GPIO10, + nxxx_gpio_interrupt, (void *)GPIO_PORT1)); + up_enable_irq(NXXX_IRQ_GPIO10); + + DEBUGVERIFY(irq_attach(NXXX_IRQ_GPIO20, + nxxx_gpio_interrupt, (void *)GPIO_PORT2)); + up_enable_irq(NXXX_IRQ_GPIO20); + + DEBUGVERIFY(irq_attach(NXXX_IRQ_GPIO30, + nxxx_gpio_interrupt, (void *)GPIO_PORT3)); + up_enable_irq(NXXX_IRQ_GPIO30); + + DEBUGVERIFY(irq_attach(NXXX_IRQ_GPIO40, + nxxx_gpio_interrupt, (void *)GPIO_PORT4)); + up_enable_irq(NXXX_IRQ_GPIO40); + + DEBUGVERIFY(irq_attach(NXXX_IRQ_GPIO50, + nxxx_gpio_interrupt, (void *)GPIO_PORT5)); + up_enable_irq(NXXX_IRQ_GPIO50); +} + +/**************************************************************************** + * Name: nxxx_gpioirq_attach + * + * Description: + * Attach a pin interrupt handler. + * + ****************************************************************************/ + +int nxxx_gpioirq_attach(gpio_pinset_t pinset, xcpt_t isr, void *arg) +{ + uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + + /* Atomically change the handler */ + + irqstate_t flags = enter_critical_section(); + + g_isrtab[port].pins[pin].isr = isr; + g_isrtab[port].pins[pin].arg = arg; + + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: nxxx_gpioirq_configure + * + * Description: + * Configure an interrupt for the specified GPIO pin. + * + ****************************************************************************/ + +int nxxx_gpioirq_configure(gpio_pinset_t pinset) +{ + uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + + /* Nothing much to do here, just reset the IRQ config */ + + putreg32(0, NXXX_GPIO_ICRN(port, pin)); + + return OK; +} + +/**************************************************************************** + * Name: nxxx_gpioirq_enable + * + * Description: + * Enable the interrupt for specified GPIO IRQ + * + ****************************************************************************/ + +int nxxx_gpioirq_enable(gpio_pinset_t pinset) +{ + uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + uint32_t both = (pinset & GPIO_INTBOTHCFG_MASK) >> GPIO_INTBOTHCFG_SHIFT; + uint32_t icr = (pinset & GPIO_INTCFG_MASK); + uint32_t regval; + uintptr_t regaddr; + + /* Perform RMW to the specific pin */ + + regaddr = NXXX_GPIO_ICRN(port, pin); + regval = getreg32(regaddr); + regval &= ~NXXX_GPIO_ICRN_MASK; + + if (both) + { + regval |= NXXX_GPIO_ICRN_BOTH; + } + else if (icr == GPIO_INT_LOWLEVEL) + { + regval |= NXXX_GPIO_ICRN_ZERO; + } + else if (icr == GPIO_INT_HIGHLEVEL) + { + regval |= NXXX_GPIO_ICRN_ONE; + } + else if (icr == GPIO_INT_RISINGEDGE) + { + regval |= NXXX_GPIO_ICRN_RISING; + } + else /* GPIO_INT_FALLINGEDGE */ + { + regval |= NXXX_GPIO_ICRN_FALLING; + } + + putreg32(regval, regaddr); + return OK; +} + +/**************************************************************************** + * Name: nxxx_gpioirq_disable + * + * Description: + * Disable the interrupt for specified GPIO IRQ + * + ****************************************************************************/ + +int nxxx_gpioirq_disable(gpio_pinset_t pinset) +{ + uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + uint32_t regval; + uintptr_t regaddr; + + /* Perform RMW to the specific pin */ + + regaddr = NXXX_GPIO_ICRN(port, pin); + regval = getreg32(regaddr); + regval &= ~NXXX_GPIO_ICRN_MASK; + + putreg32(regval, regaddr); + return OK; +} + +#endif /* CONFIG_NXXX_GPIO_IRQ */ diff --git a/arch/arm/src/mcx-nxxx/nxxx_idle.c b/arch/arm/src/mcx-nxxx/nxxx_idle.c new file mode 100644 index 0000000000000..1267527e2b0ed --- /dev/null +++ b/arch/arm/src/mcx-nxxx/nxxx_idle.c @@ -0,0 +1,82 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/nxxx_idle.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include + +#include +#include +#include + +#include + +#include "chip.h" +#include "arm_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_idle + * + * Description: + * up_idle() is the logic that will be executed when there is no other + * ready-to-run task. This is processor idle time and will continue until + * some interrupt occurs to cause a context switch from the idle task. + * + * Processing in this state may be processor-specific. e.g., this is where + * power management operations might be performed. + * + ****************************************************************************/ + +void up_idle(void) +{ +#if defined(CONFIG_SUPPRESS_INTERRUPTS) || defined(CONFIG_SUPPRESS_TIMER_INTS) + /* If the system is idle and there are no timer interrupts, then process + * "fake" timer interrupts. Hopefully, something will wake up. + */ + + nxsched_process_timer(); +#else + + /* Sleep until an interrupt occurs to save power. If power savings are + * required, the power management code should be placed here. + */ + + asm("WFI"); +#endif +} diff --git a/arch/arm/src/mcx-nxxx/nxxx_irq.c b/arch/arm/src/mcx-nxxx/nxxx_irq.c new file mode 100644 index 0000000000000..d0cf3e459bd88 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/nxxx_irq.c @@ -0,0 +1,669 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/nxxx_irq.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "nvic.h" +#include "ram_vectors.h" +#include "arm_internal.h" + +#ifdef CONFIG_NXXX_GPIO_IRQ +# include "nxxx_gpio.h" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Get a 32-bit version of the default priority */ + +#define DEFPRIORITY32 \ + (NVIC_SYSH_PRIORITY_DEFAULT << 24 | \ + NVIC_SYSH_PRIORITY_DEFAULT << 16 | \ + NVIC_SYSH_PRIORITY_DEFAULT << 8 | \ + NVIC_SYSH_PRIORITY_DEFAULT) + +/* Given the address of a NVIC ENABLE register, this is the offset to + * the corresponding CLEAR ENABLE register. + */ + +#define NVIC_ENA_OFFSET (0) +#define NVIC_CLRENA_OFFSET (NVIC_IRQ0_31_CLEAR - NVIC_IRQ0_31_ENABLE) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxxx_dumpnvic + * + * Description: + * Dump some interesting NVIC registers + * + ****************************************************************************/ + +#if defined(CONFIG_DEBUG_IRQ_INFO) +static void nxxx_dumpnvic(const char *msg, int irq) +{ + irqstate_t flags; + + flags = enter_critical_section(); + + irqinfo("NVIC (%s, irq=%d):\n", msg, irq); + irqinfo(" INTCTRL: %08x VECTAB: %08x\n", + getreg32(NVIC_INTCTRL), getreg32(NVIC_VECTAB)); +#if 0 + irqinfo(" SYSH ENABLE MEMFAULT: %08x BUSFAULT: %08x USGFAULT: %08x " + "SYSTICK: %08x\n", + getreg32(NVIC_SYSHCON_MEMFAULTENA), + getreg32(NVIC_SYSHCON_BUSFAULTENA), + getreg32(NVIC_SYSHCON_USGFAULTENA), + getreg32(NVIC_SYSTICK_CTRL_ENABLE)); +#endif + irqinfo(" IRQ ENABLE: %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ0_31_ENABLE), + getreg32(NVIC_IRQ32_63_ENABLE), + getreg32(NVIC_IRQ64_95_ENABLE), + getreg32(NVIC_IRQ96_127_ENABLE)); +#if NXXX_IRQ_NEXTINT > 128 + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ128_159_ENABLE), + getreg32(NVIC_IRQ160_191_ENABLE), + getreg32(NVIC_IRQ192_223_ENABLE), + getreg32(NVIC_IRQ224_239_ENABLE)); +#endif + irqinfo(" SYSH_PRIO: %08x %08x %08x\n", + getreg32(NVIC_SYSH4_7_PRIORITY), + getreg32(NVIC_SYSH8_11_PRIORITY), + getreg32(NVIC_SYSH12_15_PRIORITY)); + irqinfo(" IRQ PRIO: %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ0_3_PRIORITY), + getreg32(NVIC_IRQ4_7_PRIORITY), + getreg32(NVIC_IRQ8_11_PRIORITY), + getreg32(NVIC_IRQ12_15_PRIORITY)); +#if NXXX_IRQ_NEXTINT > 16 + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ16_19_PRIORITY), + getreg32(NVIC_IRQ20_23_PRIORITY), + getreg32(NVIC_IRQ24_27_PRIORITY), + getreg32(NVIC_IRQ28_31_PRIORITY)); +#endif +#if NXXX_IRQ_NEXTINT > 32 + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ32_35_PRIORITY), + getreg32(NVIC_IRQ36_39_PRIORITY), + getreg32(NVIC_IRQ40_43_PRIORITY), + getreg32(NVIC_IRQ44_47_PRIORITY)); +#endif +#if NXXX_IRQ_NEXTINT > 48 + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ48_51_PRIORITY), + getreg32(NVIC_IRQ52_55_PRIORITY), + getreg32(NVIC_IRQ56_59_PRIORITY), + getreg32(NVIC_IRQ60_63_PRIORITY)); +#endif +#if NXXX_IRQ_NEXTINT > 64 + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ64_67_PRIORITY), + getreg32(NVIC_IRQ68_71_PRIORITY), + getreg32(NVIC_IRQ72_75_PRIORITY), + getreg32(NVIC_IRQ76_79_PRIORITY)); +#endif +#if NXXX_IRQ_NEXTINT > 80 + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ80_83_PRIORITY), + getreg32(NVIC_IRQ84_87_PRIORITY), + getreg32(NVIC_IRQ88_91_PRIORITY), + getreg32(NVIC_IRQ92_95_PRIORITY)); +#endif +#if NXXX_IRQ_NEXTINT > 96 + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ96_99_PRIORITY), + getreg32(NVIC_IRQ100_103_PRIORITY), + getreg32(NVIC_IRQ104_107_PRIORITY), + getreg32(NVIC_IRQ108_111_PRIORITY)); +#endif +#if NXXX_IRQ_NEXTINT > 112 + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ112_115_PRIORITY), + getreg32(NVIC_IRQ116_119_PRIORITY), + getreg32(NVIC_IRQ120_123_PRIORITY), + getreg32(NVIC_IRQ124_127_PRIORITY)); +#endif +#if NXXX_IRQ_NEXTINT > 128 + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ128_131_PRIORITY), + getreg32(NVIC_IRQ132_135_PRIORITY), + getreg32(NVIC_IRQ136_139_PRIORITY), + getreg32(NVIC_IRQ140_143_PRIORITY)); +#endif +#if NXXX_IRQ_NEXTINT > 144 + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ144_147_PRIORITY), + getreg32(NVIC_IRQ148_151_PRIORITY), + getreg32(NVIC_IRQ152_155_PRIORITY), + getreg32(NVIC_IRQ156_159_PRIORITY)); +#endif +#if NXXX_IRQ_NEXTINT > 160 + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ160_163_PRIORITY), + getreg32(NVIC_IRQ164_167_PRIORITY), + getreg32(NVIC_IRQ168_171_PRIORITY), + getreg32(NVIC_IRQ172_175_PRIORITY)); +#endif +#if NXXX_IRQ_NEXTINT > 176 + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ176_179_PRIORITY), + getreg32(NVIC_IRQ180_183_PRIORITY), + getreg32(NVIC_IRQ184_187_PRIORITY), + getreg32(NVIC_IRQ188_191_PRIORITY)); +#endif +#if NXXX_IRQ_NEXTINT > 192 + irqinfo(" %08x %08x %08x %08x\n", + getreg32(NVIC_IRQ192_195_PRIORITY), + getreg32(NVIC_IRQ196_199_PRIORITY), + getreg32(NVIC_IRQ200_203_PRIORITY), + getreg32(NVIC_IRQ204_207_PRIORITY)); +#endif +#if NXXX_IRQ_NEXTINT > 208 + irqinfo(" %08x %08x %08x\n", + getreg32(NVIC_IRQ208_211_PRIORITY), + getreg32(NVIC_IRQ212_215_PRIORITY), + getreg32(NVIC_IRQ216_219_PRIORITY)); +#endif +#if NXXX_IRQ_NEXTINT > 218 +# warning Missing logic +#endif + + leave_critical_section(flags); +} +#else +# define nxxx_dumpnvic(msg, irq) +#endif + +/**************************************************************************** + * Name: nxxx_nmi, nxxx_pendsv, nxxx_pendsv, nxxx_reserved + * + * Description: + * Handlers for various exceptions. None are handled and all are fatal + * error conditions. The only advantage these provided over the default + * unexpected interrupt handler is that they provide a diagnostic output. + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_FEATURES +static int nxxx_nmi(int irq, void *context, void *arg) +{ + up_irq_save(); + _err("PANIC!!! NMI received\n"); + PANIC(); + return 0; +} + +static int nxxx_pendsv(int irq, void *context, void *arg) +{ + up_irq_save(); + _err("PANIC!!! PendSV received\n"); + PANIC(); + return 0; +} + +static int nxxx_reserved(int irq, void *context, void *arg) +{ + up_irq_save(); + _err("PANIC!!! Reserved interrupt\n"); + PANIC(); + return 0; +} +#endif + +/**************************************************************************** + * Name: nxxx_prioritize_syscall + * + * Description: + * Set the priority of an exception. This function may be needed + * internally even if support for prioritized interrupts is not enabled. + * + ****************************************************************************/ + +static inline void nxxx_prioritize_syscall(int priority) +{ + uint32_t regval; + + /* SVCALL is system handler 11 */ + + regval = getreg32(NVIC_SYSH8_11_PRIORITY); + regval &= ~NVIC_SYSH_PRIORITY_PR11_MASK; + regval |= (priority << NVIC_SYSH_PRIORITY_PR11_SHIFT); + putreg32(regval, NVIC_SYSH8_11_PRIORITY); +} + +/**************************************************************************** + * Name: nxxx_irqinfo + * + * Description: + * Given an IRQ number, provide the register and bit setting to enable or + * disable the irq. + * + ****************************************************************************/ + +static int nxxx_irqinfo(int irq, uintptr_t *regaddr, uint32_t *bit, + uintptr_t offset) +{ + unsigned int extint = irq - NXXX_IRQ_EXTINT; + + DEBUGASSERT(irq >= NXXX_IRQ_NMI && irq < NR_IRQS); + + /* Check for external interrupt */ + + if (irq >= NXXX_IRQ_EXTINT) + { + if (extint < 32) + { + *regaddr = (NVIC_IRQ0_31_ENABLE + offset); + *bit = 1 << extint; + } + else +#if NXXX_IRQ_NEXTINT > 32 + if (extint < 64) + { + *regaddr = (NVIC_IRQ32_63_ENABLE + offset); + *bit = 1 << (extint - 32); + } + else +#endif +#if NXXX_IRQ_NEXTINT > 64 + if (extint < 96) + { + *regaddr = (NVIC_IRQ64_95_ENABLE + offset); + *bit = 1 << (extint - 64); + } + else +#endif +#if NXXX_IRQ_NEXTINT > 96 + if (extint < 128) + { + *regaddr = (NVIC_IRQ96_127_ENABLE + offset); + *bit = 1 << (extint - 96); + } + else +#endif +#if NXXX_IRQ_NEXTINT > 128 + if (extint < 160) + { + *regaddr = (NVIC_IRQ128_159_ENABLE + offset); + *bit = 1 << (extint - 128); + } + else +#endif +#if NXXX_IRQ_NEXTINT > 160 + if (extint < 192) + { + *regaddr = (NVIC_IRQ160_191_ENABLE + offset); + *bit = 1 << (extint - 160); + } + else +#endif +#if NXXX_IRQ_NEXTINT > 192 + if (extint < 219) + { + *regaddr = (NVIC_IRQ192_223_ENABLE + offset); + *bit = 1 << (extint - 192); + } + else +#endif +#if NXXX_IRQ_NEXTINT > 218 +# error Missing logic +#endif + { + return ERROR; /* Invalid interrupt */ + } + } + + /* Handle processor exceptions. Only a few can be disabled */ + + else + { + *regaddr = NVIC_SYSHCON; + if (irq == NXXX_IRQ_MEMFAULT) + { + *bit = NVIC_SYSHCON_MEMFAULTENA; + } + else if (irq == NXXX_IRQ_BUSFAULT) + { + *bit = NVIC_SYSHCON_BUSFAULTENA; + } + else if (irq == NXXX_IRQ_USAGEFAULT) + { + *bit = NVIC_SYSHCON_USGFAULTENA; + } + else if (irq == NXXX_IRQ_SYSTICK) + { + *regaddr = NVIC_SYSTICK_CTRL; + *bit = NVIC_SYSTICK_CTRL_ENABLE; + } + else + { + return ERROR; /* Invalid or unsupported exception */ + } + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_irqinitialize + ****************************************************************************/ + +void up_irqinitialize(void) +{ + uintptr_t regaddr; + int nintlines; + int i; + + /* The NVIC ICTR register (bits 0-4) holds the number of interrupt + * lines that the NVIC supports, defined in groups of 32. That is, + * the total number of interrupt lines is up to (32*(INTLINESNUM+1)). + * + * 0 -> 32 interrupt lines, 1 enable register, 8 priority registers + * 1 -> 64 " " " ", 2 enable registers, 16 priority registers + * 2 -> 96 " " " ", 3 enable registers, 24 priority registers + * ... + */ + + nintlines = (getreg32(NVIC_ICTR) & NVIC_ICTR_INTLINESNUM_MASK) + 1; + + /* Disable all interrupts. There are nintlines interrupt enable + * registers. + */ + + for (i = nintlines, regaddr = NVIC_IRQ0_31_CLEAR; + i > 0; + i--, regaddr += 4) + { + putreg32(0xffffffff, regaddr); + } + + /* Make sure that we are using the correct vector table. The default + * vector address is 0x0000:0000 but if we are executing code that is + * positioned in SRAM or in external FLASH, then we may need to reset + * the interrupt vector so that it refers to the table in SRAM or in + * external FLASH. + */ + + putreg32((uint32_t)_vectors, NVIC_VECTAB); + +#ifdef CONFIG_ARCH_RAMVECTORS + /* If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based + * vector table that requires special initialization. + */ + + arm_ramvec_initialize(); +#endif + + /* Set all interrupts (and exceptions) to the default priority */ + + putreg32(DEFPRIORITY32, NVIC_SYSH4_7_PRIORITY); + putreg32(DEFPRIORITY32, NVIC_SYSH8_11_PRIORITY); + putreg32(DEFPRIORITY32, NVIC_SYSH12_15_PRIORITY); + + /* Now set all of the interrupt lines to the default priority. There are + * nintlines * 8 priority registers. + */ + + for (i = (nintlines << 3), regaddr = NVIC_IRQ0_3_PRIORITY; + i > 0; + i--, regaddr += 4) + { + putreg32(DEFPRIORITY32, regaddr); + } + + /* Attach the SVCall and Hard Fault exception handlers. The SVCall + * exception is used for performing context switches; The Hard Fault + * must also be caught because a SVCall may show up as a Hard Fault + * under certain conditions. + */ + + irq_attach(NXXX_IRQ_SVCALL, arm_svcall, NULL); + irq_attach(NXXX_IRQ_HARDFAULT, arm_hardfault, NULL); + + /* Set the priority of the SVCall interrupt */ + +#ifdef CONFIG_ARCH_IRQPRIO + /* up_prioritize_irq(NXXX_IRQ_PENDSV, NVIC_SYSH_PRIORITY_MIN); */ +#endif + nxxx_prioritize_syscall(NVIC_SYSH_SVCALL_PRIORITY); + + /* If the MPU is enabled, then attach and enable the Memory Management + * Fault handler. + */ + +#ifdef CONFIG_ARM_MPU + irq_attach(NXXX_IRQ_MEMFAULT, arm_memfault, NULL); + up_enable_irq(NXXX_IRQ_MEMFAULT); +#endif + + /* Attach all other processor exceptions (except reset and sys tick) */ + +#ifdef CONFIG_DEBUG_FEATURES + irq_attach(NXXX_IRQ_NMI, nxxx_nmi, NULL); +#ifndef CONFIG_ARM_MPU + irq_attach(NXXX_IRQ_MEMFAULT, arm_memfault, NULL); +#endif + irq_attach(NXXX_IRQ_BUSFAULT, arm_busfault, NULL); + irq_attach(NXXX_IRQ_USAGEFAULT, arm_usagefault, NULL); + irq_attach(NXXX_IRQ_PENDSV, nxxx_pendsv, NULL); + arm_enable_dbgmonitor(); + irq_attach(NXXX_IRQ_DBGMONITOR, arm_dbgmonitor, NULL); + irq_attach(NXXX_IRQ_RESERVED, nxxx_reserved, NULL); +#endif + + nxxx_dumpnvic("initial", NR_IRQS); + +#ifndef CONFIG_SUPPRESS_INTERRUPTS + /* Initialize logic to support a second level of interrupt decoding for + * GPIO pins. + */ + +#ifdef CONFIG_NXXX_GPIO_IRQ + nxxx_gpioirq_initialize(); +#endif + + /* And finally, enable interrupts */ + + up_irq_enable(); +#endif +} + +/**************************************************************************** + * Name: up_disable_irq + * + * Description: + * Disable the IRQ specified by 'irq' + * + ****************************************************************************/ + +void up_disable_irq(int irq) +{ + uintptr_t regaddr; + uint32_t regval; + uint32_t bit; + + if (nxxx_irqinfo(irq, ®addr, &bit, NVIC_CLRENA_OFFSET) == 0) + { + /* Modify the appropriate bit in the register to disable the interrupt. + * For normal interrupts, we need to set the bit in the associated + * Interrupt Clear Enable register. For other exceptions, we need to + * clear the bit in the System Handler Control and State Register. + */ + + if (irq >= NXXX_IRQ_EXTINT) + { + putreg32(bit, regaddr); + } + else + { + regval = getreg32(regaddr); + regval &= ~bit; + putreg32(regval, regaddr); + } + } +#ifdef CONFIG_NXXX_GPIO_IRQ + else + { + /* Maybe it is a (derived) GPIO IRQ */ + + nxxx_gpioirq_disable(irq); + } +#endif + +#if 0 /* Might be useful in early bring-up */ + nxxx_dumpnvic("disable", irq); +#endif +} + +/**************************************************************************** + * Name: up_enable_irq + * + * Description: + * Enable the IRQ specified by 'irq' + * + ****************************************************************************/ + +void up_enable_irq(int irq) +{ + uintptr_t regaddr; + uint32_t regval; + uint32_t bit; + + if (nxxx_irqinfo(irq, ®addr, &bit, NVIC_ENA_OFFSET) == 0) + { + /* Modify the appropriate bit in the register to enable the interrupt. + * For normal interrupts, we need to set the bit in the associated + * Interrupt Set Enable register. For other exceptions, we need to + * set the bit in the System Handler Control and State Register. + */ + + if (irq >= NXXX_IRQ_EXTINT) + { + putreg32(bit, regaddr); + } + else + { + regval = getreg32(regaddr); + regval |= bit; + putreg32(regval, regaddr); + } + } +#ifdef CONFIG_NXXX_GPIO_IRQ + else + { + /* Maybe it is a (derived) GPIO IRQ */ + + nxxx_gpioirq_enable(irq); + } +#endif + +#if 0 /* Might be useful in early bring-up */ + nxxx_dumpnvic("enable", irq); +#endif +} + +/**************************************************************************** + * Name: arm_ack_irq + * + * Description: + * Acknowledge the IRQ + * + ****************************************************************************/ + +void arm_ack_irq(int irq) +{ +} + +/**************************************************************************** + * Name: up_prioritize_irq + * + * Description: + * Set the priority of an IRQ. + * + * Since this API is not supported on all architectures, it should be + * avoided in common implementations where possible. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_IRQPRIO +int up_prioritize_irq(int irq, int priority) +{ + uint32_t regaddr; + uint32_t regval; + int shift; + + DEBUGASSERT(irq >= NXXX_IRQ_MEMFAULT && irq < NR_IRQS && + (unsigned)priority <= NVIC_SYSH_PRIORITY_MIN); + + if (irq < NXXX_IRQ_EXTINT) + { + /* NVIC_SYSH_PRIORITY() maps {0..15} to one of three priority + * registers (0-3 are invalid) + */ + + regaddr = NVIC_SYSH_PRIORITY(irq); + irq -= 4; + } + else + { + /* NVIC_IRQ_PRIORITY() maps {0..} to one of many priority registers */ + + irq -= NXXX_IRQ_EXTINT; + regaddr = NVIC_IRQ_PRIORITY(irq); + } + + regval = getreg32(regaddr); + shift = ((irq & 3) << 3); + regval &= ~(0xff << shift); + regval |= (priority << shift); + putreg32(regval, regaddr); + + nxxx_dumpnvic("prioritize", irq); + return OK; +} +#endif diff --git a/arch/arm/src/mcx-nxxx/nxxx_lowputc.c b/arch/arm/src/mcx-nxxx/nxxx_lowputc.c new file mode 100644 index 0000000000000..6b696e9c29e29 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/nxxx_lowputc.c @@ -0,0 +1,599 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/nxxx_lowputc.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "nxxx_lowputc.h" + +#include + +#include +#include +#include +#include + +#include "arm_internal.h" + +#include +#include "hardware/nxxx_clock.h" +#include "hardware/nxxx_flexcomm.h" +#include "hardware/nxxx_lpuart.h" + +#include "nxxx_clockconfig.h" +#include "nxxx_port.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#if defined(CONFIG_LPUART0_SERIAL_CONSOLE) +# define NXXX_CONSOLE_DEVNUM 0 +# define NXXX_CONSOLE_BASE NXXX_LPUART0_BASE +# define NXXX_CONSOLE_BAUD CONFIG_LPUART0_BAUD +# define NXXX_CONSOLE_BITS CONFIG_LPUART0_BITS +# define NXXX_CONSOLE_PARITY CONFIG_LPUART0_PARITY +# define NXXX_CONSOLE_2STOP CONFIG_LPUART0_2STOP +#elif defined(CONFIG_LPUART2_SERIAL_CONSOLE) +# define NXXX_CONSOLE_DEVNUM 1 +# define NXXX_CONSOLE_BASE NXXX_LPUART1_BASE +# define NXXX_CONSOLE_BAUD CONFIG_LPUART1_BAUD +# define NXXX_CONSOLE_BITS CONFIG_LPUART1_BITS +# define NXXX_CONSOLE_PARITY CONFIG_LPUART1_PARITY +# define NXXX_CONSOLE_2STOP CONFIG_LPUART1_2STOP +#elif defined(CONFIG_LPUART2_SERIAL_CONSOLE) +# define NXXX_CONSOLE_DEVNUM 2 +# define NXXX_CONSOLE_BASE NXXX_LPUART2_BASE +# define NXXX_CONSOLE_BAUD CONFIG_LPUART2_BAUD +# define NXXX_CONSOLE_BITS CONFIG_LPUART2_BITS +# define NXXX_CONSOLE_PARITY CONFIG_LPUART2_PARITY +# define NXXX_CONSOLE_2STOP CONFIG_LPUART2_2STOP +#elif defined(CONFIG_LPUART3_SERIAL_CONSOLE) +# define NXXX_CONSOLE_DEVNUM 3 +# define NXXX_CONSOLE_BASE NXXX_LPUART3_BASE +# define NXXX_CONSOLE_BAUD CONFIG_LPUART3_BAUD +# define NXXX_CONSOLE_BITS CONFIG_LPUART3_BITS +# define NXXX_CONSOLE_PARITY CONFIG_LPUART3_PARITY +# define NXXX_CONSOLE_2STOP CONFIG_LPUART3_2STOP +#elif defined(CONFIG_LPUART4_SERIAL_CONSOLE) +# define NXXX_CONSOLE_DEVNUM 4 +# define NXXX_CONSOLE_BASE NXXX_LPUART4_BASE +# define NXXX_CONSOLE_BAUD CONFIG_LPUART4_BAUD +# define NXXX_CONSOLE_BITS CONFIG_LPUART4_BITS +# define NXXX_CONSOLE_PARITY CONFIG_LPUART4_PARITY +# define NXXX_CONSOLE_2STOP CONFIG_LPUART4_2STOP +#elif defined(CONFIG_LPUART5_SERIAL_CONSOLE) +# define NXXX_CONSOLE_DEVNUM 5 +# define NXXX_CONSOLE_BASE NXXX_LPUART5_BASE +# define NXXX_CONSOLE_BAUD CONFIG_LPUART5_BAUD +# define NXXX_CONSOLE_BITS CONFIG_LPUART5_BITS +# define NXXX_CONSOLE_PARITY CONFIG_LPUART5_PARITY +# define NXXX_CONSOLE_2STOP CONFIG_LPUART5_2STOP +#elif defined(CONFIG_LPUART6_SERIAL_CONSOLE) +# define NXXX_CONSOLE_DEVNUM 6 +# define NXXX_CONSOLE_BASE NXXX_LPUART6_BASE +# define NXXX_CONSOLE_BAUD CONFIG_LPUART6_BAUD +# define NXXX_CONSOLE_BITS CONFIG_LPUART6_BITS +# define NXXX_CONSOLE_PARITY CONFIG_LPUART6_PARITY +# define NXXX_CONSOLE_2STOP CONFIG_LPUART6_2STOP +#elif defined(CONFIG_LPUART7_SERIAL_CONSOLE) +# define NXXX_CONSOLE_DEVNUM 7 +# define NXXX_CONSOLE_BASE NXXX_LPUART7_BASE +# define NXXX_CONSOLE_BAUD CONFIG_LPUART7_BAUD +# define NXXX_CONSOLE_BITS CONFIG_LPUART7_BITS +# define NXXX_CONSOLE_PARITY CONFIG_LPUART7_PARITY +# define NXXX_CONSOLE_2STOP CONFIG_LPUART7_2STOP +#endif + +/* Clocking *****************************************************************/ + +/* Functional clocking is provided via the PCC. The PCC clocking must + * be configured by board-specific logic prior to using the LPUART. + */ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef NXXX_CONSOLE_BASE +static const struct uart_config_s g_console_config = +{ + .baud = NXXX_CONSOLE_BAUD, /* Configured baud */ + .parity = NXXX_CONSOLE_PARITY, /* 0=none, 1=odd, 2=even */ + .bits = NXXX_CONSOLE_BITS, /* Number of bits (5-9) */ + .stopbits2 = NXXX_CONSOLE_2STOP, /* true: Configure with 2 stop bits instead of 1 */ +}; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxxx_lowsetup + * + * Description: + * Called at the very beginning of _start. Performs low level + * initialization including setup of the console UART. This UART done + * early so that the serial console is available for debugging very early + * in the boot sequence. + * + ****************************************************************************/ + +void nxxx_lowsetup(void) +{ +#ifdef CONFIG_NXXX_LPUART0 + /* Configure LPUART0 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + nxxx_port_configure(PORT_LPUART0_RX); + nxxx_port_configure(PORT_LPUART0_TX); +#ifdef CONFIG_LPUART1_OFLOWCONTROL + nxxx_port_configure(PORT_LPUART0_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL))) + nxxx_port_configure(PORT_LPUART0_RTS); +#endif +#endif + +#ifdef CONFIG_NXXX_LPUART1 + /* Configure LPUART1 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + nxxx_port_configure(PORT_LPUART1_RX); + nxxx_port_configure(PORT_LPUART1_TX); +#ifdef CONFIG_LPUART1_OFLOWCONTROL + nxxx_port_configure(PORT_LPUART1_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL))) + nxxx_port_configure(PORT_LPUART1_RTS); +#endif +#endif + +#ifdef CONFIG_NXXX_LPUART2 + + /* Configure LPUART2 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + nxxx_port_configure(PORT_LPUART2_RX); + nxxx_port_configure(PORT_LPUART2_TX); +#ifdef CONFIG_LPUART2_OFLOWCONTROL + nxxx_port_configure(PORT_LPUART2_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL))) + nxxx_port_configure(PORT_LPUART2_RTS); +#endif +#endif + +#ifdef CONFIG_NXXX_LPUART3 + + /* Configure LPUART3 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + nxxx_port_configure(PORT_LPUART3_RX); + nxxx_port_configure(PORT_LPUART3_TX); +#ifdef CONFIG_LPUART3_OFLOWCONTROL + nxxx_port_configure(PORT_LPUART3_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART3_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART3_IFLOWCONTROL))) + nxxx_port_configure(PORT_LPUART3_RTS); +#endif +#endif + +#ifdef CONFIG_NXXX_LPUART4 + + /* Configure LPUART4 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + nxxx_port_configure(PORT_LPUART4_RX); + nxxx_port_configure(PORT_LPUART4_TX); +#ifdef CONFIG_LPUART4_OFLOWCONTROL + nxxx_port_configure(PORT_LPUART4_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART4_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART4_IFLOWCONTROL))) + nxxx_port_configure(PORT_LPUART4_RTS); +#endif +#endif + +#ifdef CONFIG_NXXX_LPUART5 + + /* Configure LPUART5 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + nxxx_port_configure(PORT_LPUART5_RX); + nxxx_port_configure(PORT_LPUART5_TX); +#ifdef CONFIG_LPUART5_OFLOWCONTROL + nxxx_port_configure(PORT_LPUART5_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART5_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART5_IFLOWCONTROL))) + nxxx_port_configure(PORT_LPUART5_RTS); +#endif +#endif + +#ifdef CONFIG_NXXX_LPUART6 + + /* Configure LPUART6 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + nxxx_port_configure(PORT_LPUART6_RX); + nxxx_port_configure(PORT_LPUART6_TX); +#ifdef CONFIG_LPUART6_OFLOWCONTROL + nxxx_port_configure(PORT_LPUART6_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART6_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART6_IFLOWCONTROL))) + nxxx_port_configure(PORT_LPUART6_RTS); +#endif +#endif + +#ifdef CONFIG_NXXX_LPUART7 + + /* Configure LPUART7 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + nxxx_port_configure(PORT_LPUART7_RX); + nxxx_port_configure(PORT_LPUART7_TX); +#ifdef CONFIG_LPUART7_OFLOWCONTROL + nxxx_port_configure(PORT_LPUART7_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART7_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART7_IFLOWCONTROL))) + nxxx_port_configure(PORT_LPUART7_RTS); +#endif +#endif + +#ifdef NXXX_CONSOLE_BASE + /* Configure the serial console for initial, non-interrupt driver mode */ + + nxxx_lpuart_configure(NXXX_CONSOLE_BASE, NXXX_CONSOLE_DEVNUM, + &g_console_config); +#endif +} + +/**************************************************************************** + * Name: nxxx_lpuart_configure + * + * Description: + * Configure a UART for non-interrupt driven operation + * + ****************************************************************************/ + +int nxxx_lpuart_configure(uint32_t base, int uartnum, + const struct uart_config_s *config) +{ + uint32_t lpuart_freq = 12000000u; + struct clock_regs_s clock_regs; + struct clock_gate_reg_s clock_gate; + uint32_t clock_source; + uint32_t psel_reg; + uint16_t sbr; + uint16_t temp_sbr; + uint32_t osr; + uint32_t temp_osr; + int temp_diff; + int configured_baud = config->baud; + int calculated_baud; + int baud_diff; + uint32_t regval; + + switch (base) + { + case NXXX_LPUART0_BASE: + clock_regs = SYSCON_FCCLK0; + clock_source = FRO12M_TO_FLEXCOMM0; + clock_gate = CLOCK_GATE_LPFLEXCOMM0; + psel_reg = NXXX_FLEXCOMM0_PSELID; + break; + + case NXXX_LPUART1_BASE: + clock_regs = SYSCON_FCCLK1; + clock_source = FRO12M_TO_FLEXCOMM1; + clock_gate = CLOCK_GATE_LPFLEXCOMM1; + psel_reg = NXXX_FLEXCOMM1_PSELID; + break; + + case NXXX_LPUART2_BASE: + clock_regs = SYSCON_FCCLK2; + clock_source = FRO12M_TO_FLEXCOMM2; + clock_gate = CLOCK_GATE_LPFLEXCOMM2; + psel_reg = NXXX_FLEXCOMM2_PSELID; + break; + + case NXXX_LPUART3_BASE: + clock_regs = SYSCON_FCCLK3; + clock_source = FRO12M_TO_FLEXCOMM3; + clock_gate = CLOCK_GATE_LPFLEXCOMM3; + psel_reg = NXXX_FLEXCOMM3_PSELID; + break; + + case NXXX_LPUART4_BASE: + clock_regs = SYSCON_FCCLK4; + clock_source = FRO12M_TO_FLEXCOMM4; + clock_gate = CLOCK_GATE_LPFLEXCOMM4; + psel_reg = NXXX_FLEXCOMM4_PSELID; + break; + + case NXXX_LPUART5_BASE: + clock_regs = SYSCON_FCCLK5; + clock_source = FRO12M_TO_FLEXCOMM5; + clock_gate = CLOCK_GATE_LPFLEXCOMM5; + psel_reg = NXXX_FLEXCOMM5_PSELID; + break; + + case NXXX_LPUART6_BASE: + clock_regs = SYSCON_FCCLK6; + clock_source = FRO12M_TO_FLEXCOMM6; + clock_gate = CLOCK_GATE_LPFLEXCOMM6; + psel_reg = NXXX_FLEXCOMM6_PSELID; + break; + + case NXXX_LPUART7_BASE: + clock_regs = SYSCON_FCCLK7; + clock_source = FRO12M_TO_FLEXCOMM7; + clock_gate = CLOCK_GATE_LPFLEXCOMM7; + psel_reg = NXXX_FLEXCOMM7_PSELID; + break; + + default: + return ERROR; + } + + /* Set FRO12MHz with divider of 1 */ + + nxxx_set_periphclock(clock_regs, clock_source, 1); + nxxx_set_clock_gate(clock_gate, true); + + /* Set FLEXCOMM as LPUART */ + + putreg32(FLEXCOMM_PSELID_PERSEL_USART, psel_reg); + + /* This LPUART instantiation uses a slightly different baud rate + * calculation. The idea is to use the best OSR (over-sampling rate) + * possible. + * + * NOTE: OSR is typically hard-set to 16 in other LPUART instantiations + * loop to find the best OSR value possible, one that generates minimum + * baud_diff iterate through the rest of the supported values of OSR + */ + + baud_diff = configured_baud; + osr = 0; + sbr = 0; + + for (temp_osr = 4; temp_osr <= 32; temp_osr++) + { + /* Calculate the temporary sbr value */ + + temp_sbr = (lpuart_freq / (configured_baud * temp_osr)); + + /* Set temp_sbr to 1 if the sourceClockInHz can not satisfy the + * desired baud rate. + */ + + if (temp_sbr == 0) + { + temp_sbr = 1; + } + + /* Calculate the baud rate based on the temporary OSR and SBR values */ + + calculated_baud = (lpuart_freq / (temp_osr * temp_sbr)); + temp_diff = abs(calculated_baud - configured_baud); + + /* Select the better value between srb and (sbr + 1) */ + + calculated_baud = (lpuart_freq / (temp_osr * (temp_sbr + 1))); + if (temp_diff > + abs(calculated_baud - configured_baud)) + { + temp_diff = abs(calculated_baud - configured_baud); + temp_sbr++; + } + + if (temp_diff <= baud_diff) + { + baud_diff = temp_diff; + osr = temp_osr; + sbr = temp_sbr; + } + } + + if (baud_diff > ((configured_baud * 3) / 100)) + { + /* Unacceptable baud rate difference of more than 3% */ + + return ERROR; + } + + /* Reset all internal logic and registers, except the Global Register */ + + regval = getreg32(base + NXXX_LPUART_GLOBAL_OFFSET); + regval |= LPUART_GLOBAL_RST; + putreg32(regval, base + NXXX_LPUART_GLOBAL_OFFSET); + + regval &= ~LPUART_GLOBAL_RST; + putreg32(regval, base + NXXX_LPUART_GLOBAL_OFFSET); + + /* Enable RX and TX FIFOs */ + + putreg32(LPUART_FIFO_RXFE | LPUART_FIFO_TXFE, + base + NXXX_LPUART_FIFO_OFFSET); + + /* Construct MODIR register */ + + regval = 0; + + if (config->userts) + { + regval |= LPUART_MODIR_RXRTSE; + } + else if (config->users485) + { + /* Both TX and RX side can't control RTS, so this gives + * the RX side precedence. This should have been filtered + * in layers above anyway, but it's just a precaution. + */ + + regval |= LPUART_MODIR_TXRTSE; + } + + if (config->usects) + { + regval |= LPUART_MODIR_TXCTSE; + } + + if (config->invrts) + { + regval |= LPUART_MODIR_TXRTSPOL; + } + + putreg32(regval, base + NXXX_LPUART_MODIR_OFFSET); + + regval = 0; + + if ((osr > 3) && (osr < 8)) + { + regval |= LPUART_BAUD_BOTHEDGE; + } + + if (config->stopbits2) + { + regval |= LPUART_BAUD_SBNS; + } + + regval |= LPUART_BAUD_OSR(osr) | LPUART_BAUD_SBR(sbr); + putreg32(regval, base + NXXX_LPUART_BAUD_OFFSET); + + regval = 0; + if (config->parity == 1) + { + regval |= LPUART_CTRL_PE | LPUART_CTRL_PT_ODD; + } + else if (config->parity == 2) + { + regval |= LPUART_CTRL_PE | LPUART_CTRL_PT_EVEN; + } + + if (config->bits == 9 || (config->bits == 8 && config->parity != 0)) + { + regval |= LPUART_CTRL_M; + } + else if ((config->bits == 8)) + { + regval &= ~LPUART_CTRL_M; + } + else + { + /* REVISIT: Here should be added support of other bit modes. */ + + return -ENOSYS; + } + + regval |= LPUART_CTRL_RE | LPUART_CTRL_TE; + putreg32(regval, base + NXXX_LPUART_CTRL_OFFSET); + + return OK; +} + +/**************************************************************************** + * Name: arm_earlyprintinit + * + * Description: + * Configure LPUART1 for non-interrupt driven operation + * + ****************************************************************************/ + +void arm_earlyprintinit(char ch) +{ + /* Assume bootloader has already set up the LPUART1 */ +} + +/**************************************************************************** + * Name: arm_lowputc + * + * Description: + * Output a byte with as few system dependencies as possible. This will + * even work BEFORE the console is initialized if we are booting from U- + * Boot (and the same UART is used for the console, of course.) + * + ****************************************************************************/ + +void arm_lowputc(char ch) +{ +#ifdef NXXX_CONSOLE_BASE + while ((getreg32(NXXX_CONSOLE_BASE + NXXX_LPUART_STAT_OFFSET) & + LPUART_STAT_TDRE) == 0) + { + } + + /* If the character to output is a newline, + * then pre-pend a carriage return + */ + + if (ch == '\n') + { + /* Send the carriage return by writing it into the UART_TXD register. */ + + putreg32((uint32_t)'\r', + NXXX_CONSOLE_BASE + NXXX_LPUART_DATA_OFFSET); + + /* Wait for the transmit register to be emptied. When the TXFE bit is + * non-zero, the TX Buffer FIFO is empty. + */ + + while ((getreg32(NXXX_CONSOLE_BASE + NXXX_LPUART_STAT_OFFSET) & + LPUART_STAT_TDRE) == 0) + { + } + } + + /* Send the character by writing it into the UART_TXD register. */ + + putreg32((uint32_t)ch, NXXX_CONSOLE_BASE + NXXX_LPUART_DATA_OFFSET); + + /* Wait for the transmit register to be emptied. When the TXFE bit is + * non-zero, the TX Buffer FIFO is empty. + */ + + while ((getreg32(NXXX_CONSOLE_BASE + NXXX_LPUART_STAT_OFFSET) & + LPUART_STAT_TDRE) == 0) + { + } +#endif +} diff --git a/arch/arm/src/mcx-nxxx/nxxx_lowputc.h b/arch/arm/src/mcx-nxxx/nxxx_lowputc.h new file mode 100644 index 0000000000000..f50edf9c49b8e --- /dev/null +++ b/arch/arm/src/mcx-nxxx/nxxx_lowputc.h @@ -0,0 +1,95 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/nxxx_lowputc.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_MCX_NXXX_NXXX_LOWPUTC_H +#define __ARCH_ARM_SRC_MCX_NXXX_NXXX_LOWPUTC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include +#include + +#include "arm_internal.h" + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* This structure describes the configuration of an UART */ + +struct uart_config_s +{ + uint32_t baud; /* Configured baud */ + uint8_t parity; /* 0=none, 1=odd, 2=even */ + uint8_t bits; /* Number of bits (5-9) */ + bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */ + bool userts; /* True: Assert RTS when there are data to be sent */ + bool invrts; /* True: Invert sense of RTS pin (true=active high) */ + bool usects; /* True: Condition transmission on CTS asserted */ + bool users485; /* True: Assert RTS while transmission progresses */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/**************************************************************************** + * Name: nxxx_lowsetup + * + * Description: + * Called at the very beginning of _start. Performs low level + * initialization including setup of the console UART. This UART done + * early so that the serial console is available for debugging very early + * in the boot sequence. + * + ****************************************************************************/ + +void nxxx_lowsetup(void); + +/**************************************************************************** + * Name: nxxx_lpuart_configure + * + * Description: + * Configure a UART for non-interrupt driven operation + * + ****************************************************************************/ + +int nxxx_lpuart_configure(uint32_t base, + int uartnum, + const struct uart_config_s *config); + +#ifdef __cplusplus +} +#endif + +#endif /* __ARCH_ARM_SRC_MCX_NXXX_NXXX_LOWPUTC_H */ diff --git a/arch/arm/src/mcx-nxxx/nxxx_lpuart.c b/arch/arm/src/mcx-nxxx/nxxx_lpuart.c new file mode 100644 index 0000000000000..4f3a31dcc34a5 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/nxxx_lpuart.c @@ -0,0 +1,2656 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/nxxx_lpuart.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SERIAL_TERMIOS +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "arm_internal.h" +#include "hardware/nxxx_lpuart.h" +#include "hardware/nxxx_port.h" +#include "nxxx_lowputc.h" +#include "nxxx_serial.h" + +#if defined(SERIAL_HAVE_TXDMA) || defined(SERIAL_HAVE_RXDMA) +# include "chip.h" +# include "nxxx_edma.h" +# include "hardware/nxxx_dmamux.h" +#endif + +#ifdef USE_SERIALDRIVER + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* DMA should be 32-byte aligned. There is no dcache. */ + +#define DMA_ALIGNMENT 32 +#define RXDMA_BUFFER_MASK (DMA_ALIGNMENT - 1) +#define RXDMA_BUFFER_SIZE ((CONFIG_NXXX_SERIAL_RXDMA_BUFFER_SIZE \ + + RXDMA_BUFFER_MASK) & ~RXDMA_BUFFER_MASK) +#define TXDMA_BUFFER_MASK (DMA_ALIGNMENT - 1) +#define TXDMA_BUFFER_SIZE ((CONFIG_NXXX_SERIAL_RXDMA_BUFFER_SIZE \ + + RXDMA_BUFFER_MASK) & ~RXDMA_BUFFER_MASK) + +/* Buffers need to be aligned and multiples of DMA_ALIGNMENT */ + +#if defined(CONFIG_ARM64_DCACHE_DISABLE) +# define TXDMA_BUF_SIZE(b) (b) +# define TXDMA_BUF_ALIGN +#else +# define TXDMA_BUF_SIZE(b) (((b) + TXDMA_BUFFER_MASK) & ~TXDMA_BUFFER_MASK) +# define TXDMA_BUF_ALIGN aligned_data(DMA_ALIGNMENT); +#endif + +#if !defined(CONFIG_LPUART0_TXDMA) +# define LPUART0_TXBUFSIZE_ADJUSTED CONFIG_LPUART0_TXBUFSIZE +# define LPUART0_TXBUFSIZE_ALGN +#else +# define LPUART0_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART0_TXBUFSIZE) +# define LPUART0_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART1_TXDMA) +# define LPUART1_TXBUFSIZE_ADJUSTED CONFIG_LPUART1_TXBUFSIZE +# define LPUART1_TXBUFSIZE_ALGN +#else +# define LPUART1_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART1_TXBUFSIZE) +# define LPUART1_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART2_TXDMA) +# define LPUART2_TXBUFSIZE_ADJUSTED CONFIG_LPUART2_TXBUFSIZE +# define LPUART2_TXBUFSIZE_ALGN +#else +# define LPUART2_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART2_TXBUFSIZE) +# define LPUART2_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART3_TXDMA) +# define LPUART3_TXBUFSIZE_ADJUSTED CONFIG_LPUART3_TXBUFSIZE +# define LPUART3_TXBUFSIZE_ALGN +#else +# define LPUART3_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART3_TXBUFSIZE) +# define LPUART3_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART4_TXDMA) +# define LPUART4_TXBUFSIZE_ADJUSTED CONFIG_LPUART4_TXBUFSIZE +# define LPUART4_TXBUFSIZE_ALGN +#else +# define LPUART4_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART4_TXBUFSIZE) +# define LPUART4_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART5_TXDMA) +# define LPUART5_TXBUFSIZE_ADJUSTED CONFIG_LPUART5_TXBUFSIZE +# define LPUART5_TXBUFSIZE_ALGN +#else +# define LPUART5_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART5_TXBUFSIZE) +# define LPUART5_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART6_TXDMA) +# define LPUART6_TXBUFSIZE_ADJUSTED CONFIG_LPUART6_TXBUFSIZE +# define LPUART6_TXBUFSIZE_ALGN +#else +# define LPUART6_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART6_TXBUFSIZE) +# define LPUART6_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART7_TXDMA) +# define LPUART7_TXBUFSIZE_ADJUSTED CONFIG_LPUART7_TXBUFSIZE +# define LPUART7_TXBUFSIZE_ALGN +#else +# define LPUART7_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART7_TXBUFSIZE) +# define LPUART7_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +/* Which LPUART with be console? */ + +#if defined(CONFIG_LPUART0_SERIAL_CONSOLE) +# define CONSOLE_DEV g_lpuart0priv /* LPUART0 is console */ +# if defined(CONFIG_LPUART0_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART0_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif +#elif defined(CONFIG_LPUART1_SERIAL_CONSOLE) +# define CONSOLE_DEV g_lpuart1priv /* LPUART1 is console */ +# if defined(CONFIG_LPUART1_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART1_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif +#elif defined(CONFIG_LPUART2_SERIAL_CONSOLE) +# define CONSOLE_DEV g_lpuart2priv /* LPUART2 is console */ +# if defined(CONFIG_LPUART2_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART2_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif +#elif defined(CONFIG_LPUART3_SERIAL_CONSOLE) +# define CONSOLE_DEV g_lpuart3priv /* LPUART3 is console */ +# if defined(CONFIG_LPUART3_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART3_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif +#elif defined(CONFIG_LPUART4_SERIAL_CONSOLE) +# define CONSOLE_DEV g_lpuart4priv /* LPUART4 is console */ +# if defined(CONFIG_LPUART4_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART4_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif +#elif defined(CONFIG_LPUART5_SERIAL_CONSOLE) +# define CONSOLE_DEV g_lpuart5priv /* LPUART5 is console */ +# if defined(CONFIG_LPUART5_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART5_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif +#elif defined(CONFIG_LPUART6_SERIAL_CONSOLE) +# define CONSOLE_DEV g_lpuart6priv /* LPUART6 is console */ +# if defined(CONFIG_LPUART6_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART6_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif +#elif defined(CONFIG_LPUART7_SERIAL_CONSOLE) +# define CONSOLE_DEV g_lpuart7priv /* LPUART7 is console */ +# if defined(CONFIG_LPUART7_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART7_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif +#endif + +#if defined(SERIAL_HAVE_CONSOLE_RXDMA) || defined(SERIAL_HAVE_CONSOLE_TXDMA) +# define SERIAL_HAVE_CONSOLE_DMA +#endif + +#ifdef CONFIG_NXXX_LPUART0 +#define TTYS0_DEV g_lpuart0priv /* LPUART0 is ttyS0 */ +#endif + +#ifdef CONFIG_NXXX_LPUART1 +#define TTYS1_DEV g_lpuart1priv /* LPUART1 is ttyS1 */ +#endif + +#ifdef CONFIG_NXXX_LPUART2 +#define TTYS2_DEV g_lpuart2priv /* LPUART2 is ttyS2 */ +#endif + +#ifdef CONFIG_NXXX_LPUART3 +#define TTYS3_DEV g_lpuart3priv /* LPUART3 is ttyS3 */ +#endif + +#ifdef CONFIG_NXXX_LPUART4 +#define TTYS4_DEV g_lpuart4priv /* LPUART4 is ttyS4 */ +#endif + +#ifdef CONFIG_NXXX_LPUART5 +#define TTYS5_DEV g_lpuart5priv /* LPUART5 is ttyS5 */ +#endif + +#ifdef CONFIG_NXXX_LPUART6 +#define TTYS6_DEV g_lpuart6priv /* LPUART6 is ttyS6 */ +#endif + +#ifdef CONFIG_NXXX_LPUART7 +#define TTYS7_DEV g_lpuart7priv /* LPUART7 is ttyS7 */ +#endif + +/* Power management definitions */ + +#if defined(CONFIG_PM) && !defined(CONFIG_NXXX_PM_SERIAL_ACTIVITY) +# define CONFIG_NXXX_PM_SERIAL_ACTIVITY 10 +#endif + +#if defined(CONFIG_PM) +# define PM_IDLE_DOMAIN 0 /* Revisit */ +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct nxxx_uart_s +{ + struct uart_dev_s dev; /* Generic UART device */ + + const uint32_t uartbase; /* Base address of UART registers */ + const int uartnum; /* LPUART number 1-8 */ + const bool usects; /* output flow control (CTS) available */ + const bool userts; /* input flow control (RTS) available */ + const bool rs485mode; /* We are in RS485 (RTS on TX) mode */ + const bool inviflow; /* Invert RTS sense */ + spinlock_t lock; /* Spinlock */ + uint32_t baud; /* Configured baud */ + uint32_t ie; /* Saved enabled interrupts */ + uint8_t irq; /* IRQ associated with this UART */ + uint8_t parity; /* 0=none, 1=odd, 2=even */ + uint8_t bits; /* Number of bits (7 or 8) */ + bool stopbits2; /* true: Configure with 2 stop bits vs 1 */ + bool oflow; /* output flow control (CTS) enabled */ + bool iflow; /* input flow control (RTS) enabled */ + + /* TX DMA state */ + +#ifdef SERIAL_HAVE_TXDMA + const unsigned int txch; /* DMAMUX source of TX DMA request */ + DMACH_HANDLE txdma; /* currently-open transmit DMA stream */ +#endif + + /* RX DMA state */ + +#ifdef SERIAL_HAVE_RXDMA + const unsigned int rxch; /* DMAMUX source of RX DMA request */ + DMACH_HANDLE rxdma; /* currently-open receive DMA stream */ + bool rxenable; /* DMA-based reception en/disable */ + uint32_t rxdmanext; /* Next byte in the DMA buffer to be read */ +#ifndef CONFIG_ARM64_DCACHE_DISABLE + uint32_t rxdmaavail; /* Number of bytes available without need to + * to invalidate the data cache */ +#endif + char *const rxfifo; /* Receive DMA buffer */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static inline uint32_t nxxx_serialin(struct nxxx_uart_s *priv, + uint32_t offset); +static inline void nxxx_serialout(struct nxxx_uart_s *priv, + uint32_t offset, uint32_t value); +static inline void nxxx_disableuartint(struct nxxx_uart_s *priv, + uint32_t *ie); +static inline void nxxx_restoreuartint(struct nxxx_uart_s *priv, + uint32_t ie); + +static int nxxx_setup(struct uart_dev_s *dev); +static void nxxx_shutdown(struct uart_dev_s *dev); +static int nxxx_attach(struct uart_dev_s *dev); +static void nxxx_detach(struct uart_dev_s *dev); +static int nxxx_interrupt(int irq, void *context, void *arg); +static int nxxx_ioctl(struct file *filep, int cmd, unsigned long arg); +#if !defined(SERIAL_HAVE_ONLY_RXDMA) +static int nxxx_receive(struct uart_dev_s *dev, unsigned int *status); +static void nxxx_rxint(struct uart_dev_s *dev, bool enable); +static bool nxxx_rxavailable(struct uart_dev_s *dev); +#endif +#if !defined(SERIAL_HAVE_ONLY_TXDMA) +static void nxxx_txint(struct uart_dev_s *dev, bool enable); +#endif + +static void nxxx_send(struct uart_dev_s *dev, int ch); + +static bool nxxx_txready(struct uart_dev_s *dev); + +#ifdef SERIAL_HAVE_TXDMA +static void nxxx_dma_send(struct uart_dev_s *dev); +static void nxxx_dma_txint(struct uart_dev_s *dev, bool enable); +static void nxxx_dma_txavailable(struct uart_dev_s *dev); +static void nxxx_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done, + int result); +#endif + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) +static int nxxx_dma_setup(struct uart_dev_s *dev); +static void nxxx_dma_shutdown(struct uart_dev_s *dev); +#endif + +#ifdef SERIAL_HAVE_RXDMA +static int nxxx_dma_receive(struct uart_dev_s *dev, + unsigned int *status); +#ifdef CONFIG_PM +static void nxxx_dma_reenable(struct nxxx_uart_s *priv); +#endif +static void nxxx_dma_rxint(struct uart_dev_s *dev, bool enable); +static bool nxxx_dma_rxavailable(struct uart_dev_s *dev); + +static void nxxx_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done, + int result); +#endif + +static bool nxxx_txempty(struct uart_dev_s *dev); + +#ifdef CONFIG_PM +static void up_pm_notify(struct pm_callback_s *cb, int dowmin, + enum pm_state_e pmstate); +static int up_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Serial driver UART operations */ + +#if !defined(SERIAL_HAVE_ONLY_TXDMA) && !defined(SERIAL_HAVE_ONLY_RXDMA) +static const struct uart_ops_s g_lpuart_ops = +{ + .setup = nxxx_setup, + .shutdown = nxxx_shutdown, + .attach = nxxx_attach, + .detach = nxxx_detach, + .ioctl = nxxx_ioctl, + .receive = nxxx_receive, + .rxint = nxxx_rxint, + .rxavailable = nxxx_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = NULL, +#endif + .send = nxxx_send, + .txint = nxxx_txint, + .txready = nxxx_txready, + .txempty = nxxx_txempty, +}; +#endif + +#if defined(SERIAL_HAVE_RXDMA) && defined(SERIAL_HAVE_TXDMA) +static const struct uart_ops_s g_lpuart_rxtxdma_ops = +{ + .setup = nxxx_dma_setup, + .shutdown = nxxx_dma_shutdown, + .attach = nxxx_attach, + .detach = nxxx_detach, + .ioctl = nxxx_ioctl, + .receive = nxxx_dma_receive, + .rxint = nxxx_dma_rxint, + .rxavailable = nxxx_dma_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = NULL, +#endif + .send = nxxx_send, + .txint = nxxx_dma_txint, + .txready = nxxx_txready, + .txempty = nxxx_txempty, + .dmatxavail = nxxx_dma_txavailable, + .dmasend = nxxx_dma_send, +}; +#endif + +#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_RXDMA) +static const struct uart_ops_s g_lpuart_rxdma_ops = +{ + .setup = nxxx_dma_setup, + .shutdown = nxxx_dma_shutdown, + .attach = nxxx_attach, + .detach = nxxx_detach, + .ioctl = nxxx_ioctl, + .receive = nxxx_dma_receive, + .rxint = nxxx_dma_rxint, + .rxavailable = nxxx_dma_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = NULL, +#endif + .send = nxxx_send, + .txint = nxxx_txint, + .txready = nxxx_txready, + .txempty = nxxx_txempty, +}; +#endif + +#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_TXDMA) +static const struct uart_ops_s g_lpuart_txdma_ops = +{ + .setup = nxxx_dma_setup, + .shutdown = nxxx_dma_shutdown, + .attach = nxxx_attach, + .detach = nxxx_detach, + .ioctl = nxxx_ioctl, + .receive = nxxx_receive, + .rxint = nxxx_rxint, + .rxavailable = nxxx_rxavailable, + #ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = NULL, + #endif + .send = nxxx_send, + .txint = nxxx_dma_txint, + .txready = nxxx_txready, + .txempty = nxxx_txempty, + .dmatxavail = nxxx_dma_txavailable, + .dmasend = nxxx_dma_send, +}; +#endif + +/* Avoid unused warning */ +#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_RXDMA) +const struct uart_ops_s *g_o0 = &g_lpuart_rxdma_ops; +#endif +#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_TXDMA) +const struct uart_ops_s *g_o1 = &g_lpuart_txdma_ops; +#endif + +/* I/O buffers */ + +#ifdef CONFIG_LPUART0_RXDMA +static char g_lpuart0rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(DMA_ALIGNMENT); +#endif + +#ifdef CONFIG_LPUART1_RXDMA +static char g_lpuart1rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(DMA_ALIGNMENT); +#endif + +# ifdef CONFIG_LPUART2_RXDMA +static char g_lpuart2rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(DMA_ALIGNMENT); +#endif + +#ifdef CONFIG_LPUART3_RXDMA +static char g_lpuart3rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(DMA_ALIGNMENT); +#endif + +#ifdef CONFIG_LPUART4_RXDMA +static char g_lpuart4rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(DMA_ALIGNMENT); +#endif + +#ifdef CONFIG_LPUART5_RXDMA +static char g_lpuart5rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(DMA_ALIGNMENT); +#endif + +#ifdef CONFIG_LPUART6_RXDMA +static char g_lpuart6rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(DMA_ALIGNMENT); +#endif + +#ifdef CONFIG_LPUART7_RXDMA +static char g_lpuart7rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(DMA_ALIGNMENT); +#endif + +#ifdef CONFIG_NXXX_LPUART0 +static char g_lpuart0rxbuffer[CONFIG_LPUART0_RXBUFSIZE]; +static char g_lpuart0txbuffer[LPUART0_TXBUFSIZE_ADJUSTED] \ + LPUART0_TXBUFSIZE_ALGN; +#endif + +#ifdef CONFIG_NXXX_LPUART1 +static char g_lpuart1rxbuffer[CONFIG_LPUART1_RXBUFSIZE]; +static char g_lpuart1txbuffer[LPUART1_TXBUFSIZE_ADJUSTED] + LPUART1_TXBUFSIZE_ALGN; +#endif + +#ifdef CONFIG_NXXX_LPUART2 +static char g_lpuart2rxbuffer[CONFIG_LPUART2_RXBUFSIZE]; +static char g_lpuart2txbuffer[LPUART2_TXBUFSIZE_ADJUSTED] + LPUART2_TXBUFSIZE_ALGN; +#endif + +#ifdef CONFIG_NXXX_LPUART3 +static char g_lpuart3rxbuffer[CONFIG_LPUART3_RXBUFSIZE]; +static char g_lpuart3txbuffer[LPUART3_TXBUFSIZE_ADJUSTED] + LPUART3_TXBUFSIZE_ALGN; +#endif + +#ifdef CONFIG_NXXX_LPUART4 +static char g_lpuart4rxbuffer[CONFIG_LPUART4_RXBUFSIZE]; +static char g_lpuart4txbuffer[LPUART4_TXBUFSIZE_ADJUSTED] + LPUART4_TXBUFSIZE_ALGN; +#endif + +#ifdef CONFIG_NXXX_LPUART5 +static char g_lpuart5rxbuffer[CONFIG_LPUART5_RXBUFSIZE]; +static char g_lpuart5txbuffer[LPUART5_TXBUFSIZE_ADJUSTED] + LPUART5_TXBUFSIZE_ALGN; +#endif + +#ifdef CONFIG_NXXX_LPUART6 +static char g_lpuart6rxbuffer[CONFIG_LPUART6_RXBUFSIZE]; +static char g_lpuart6txbuffer[LPUART6_TXBUFSIZE_ADJUSTED] + LPUART6_TXBUFSIZE_ALGN; +#endif + +#ifdef CONFIG_NXXX_LPUART7 +static char g_lpuart7rxbuffer[CONFIG_LPUART7_RXBUFSIZE]; +static char g_lpuart7txbuffer[LPUART7_TXBUFSIZE_ADJUSTED] + LPUART7_TXBUFSIZE_ALGN; +#endif + +#ifdef CONFIG_NXXX_LPUART0 +static struct nxxx_uart_s g_lpuart0priv = +{ + .dev = + { + .recv = + { + .size = CONFIG_LPUART0_RXBUFSIZE, + .buffer = g_lpuart0rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART0_TXBUFSIZE, + .buffer = g_lpuart0txbuffer, + }, + #if defined(CONFIG_LPUART0_RXDMA) && defined(CONFIG_LPUART0_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, + #elif defined(CONFIG_LPUART0_RXDMA) && !defined(CONFIG_LPUART0_TXDMA) + .ops = &g_lpuart_rxdma_ops, + #elif !defined(CONFIG_LPUART0_RXDMA) && defined(CONFIG_LPUART0_TXDMA) + .ops = &g_lpuart_txdma_ops, + #else + .ops = &g_lpuart_ops, + #endif + }, + + .uartbase = NXXX_LPUART0_BASE, + .uartnum = 0, + .baud = CONFIG_LPUART0_BAUD, + .irq = NXXX_IRQ_LP_FLEXCOMM0, + .parity = CONFIG_LPUART0_PARITY, + .bits = CONFIG_LPUART0_BITS, + .lock = SP_UNLOCKED, + .stopbits2 = CONFIG_LPUART0_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART0_OFLOWCONTROL) + .usects = true, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART0_IFLOWCONTROL) + .userts = true, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART0_INVERTIFLOWCONTROL) + .inviflow = true, +# endif + +# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART0_RS485RTSCONTROL) + .rs485mode = true, +# endif + +# ifdef CONFIG_LPUART0_TXDMA + .txch = DMA_REQUEST_MUXLPUART0TX, +# endif +# ifdef CONFIG_LPUART0_RXDMA + .rxch = DMA_REQUEST_MUXLPUART0RX, + .rxfifo = g_lpuart0rxfifo, +# endif +}; +#endif + +#ifdef CONFIG_NXXX_LPUART1 +static struct nxxx_uart_s g_lpuart1priv = +{ + .dev = + { + .recv = + { + .size = CONFIG_LPUART1_RXBUFSIZE, + .buffer = g_lpuart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART1_TXBUFSIZE, + .buffer = g_lpuart1txbuffer, + }, +# if defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, +# elif defined(CONFIG_LPUART1_RXDMA) && !defined(CONFIG_LPUART1_TXDMA) + .ops = &g_lpuart_rxdma_ops, +# elif !defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_TXDMA) + .ops = &g_lpuart_txdma_ops, +# else + .ops = &g_lpuart_ops, +# endif + }, + + .uartbase = NXXX_LPUART1_BASE, + .uartnum = 1, + .baud = CONFIG_LPUART1_BAUD, + .irq = NXXX_IRQ_LP_FLEXCOMM1, + .parity = CONFIG_LPUART1_PARITY, + .bits = CONFIG_LPUART1_BITS, + .lock = SP_UNLOCKED, + .stopbits2 = CONFIG_LPUART1_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART1_OFLOWCONTROL) + .usects = true, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL) + .userts = true, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART1_INVERTIFLOWCONTROL) + .inviflow = true, +# endif + +# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL) + .rs485mode = true, +# endif + +# ifdef CONFIG_LPUART1_TXDMA + .txch = DMA_REQUEST_MUXLPUART1TX, +# endif +# ifdef CONFIG_LPUART1_RXDMA + .rxch = DMA_REQUEST_MUXLPUART1RX, + .rxfifo = g_lpuart1rxfifo, +# endif +}; +#endif + +#ifdef CONFIG_NXXX_LPUART2 +static struct nxxx_uart_s g_lpuart2priv = +{ + .dev = + { + .recv = + { + .size = CONFIG_LPUART2_RXBUFSIZE, + .buffer = g_lpuart2rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART2_TXBUFSIZE, + .buffer = g_lpuart2txbuffer, + }, +# if defined(CONFIG_LPUART2_RXDMA) && defined(CONFIG_LPUART2_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, +# elif defined(CONFIG_LPUART2_RXDMA) && !defined(CONFIG_LPUART2_TXDMA) + .ops = &g_lpuart_rxdma_ops, +# elif !defined(CONFIG_LPUART2_RXDMA) && defined(CONFIG_LPUART2_TXDMA) + .ops = &g_lpuart_txdma_ops, +# else + .ops = &g_lpuart_ops, +# endif + }, + + .uartbase = NXXX_LPUART2_BASE, + .uartnum = 2, + .baud = CONFIG_LPUART2_BAUD, + .irq = NXXX_IRQ_LP_FLEXCOMM2, + .parity = CONFIG_LPUART2_PARITY, + .bits = CONFIG_LPUART2_BITS, + .lock = SP_UNLOCKED, + .stopbits2 = CONFIG_LPUART2_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART2_OFLOWCONTROL) + .usects = true, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL) + .userts = true, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART2_INVERTIFLOWCONTROL) + .inviflow = true, +# endif + +# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL) + .rs485mode = true, +# endif + +# ifdef CONFIG_LPUART2_TXDMA + .txch = DMA_REQUEST_MUXLPUART2TX, +# endif +# ifdef CONFIG_LPUART2_RXDMA + .rxch = DMA_REQUEST_MUXLPUART2RX, + .rxfifo = g_lpuart2rxfifo, +# endif +}; +#endif + +#ifdef CONFIG_NXXX_LPUART3 +static struct nxxx_uart_s g_lpuart3priv = +{ + .dev = + { + .recv = + { + .size = CONFIG_LPUART3_RXBUFSIZE, + .buffer = g_lpuart3rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART3_TXBUFSIZE, + .buffer = g_lpuart3txbuffer, + }, +# if defined(CONFIG_LPUART3_RXDMA) && defined(CONFIG_LPUART3_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, +# elif defined(CONFIG_LPUART3_RXDMA) && !defined(CONFIG_LPUART3_TXDMA) + .ops = &g_lpuart_rxdma_ops, +# elif !defined(CONFIG_LPUART3_RXDMA) && defined(CONFIG_LPUART3_TXDMA) + .ops = &g_lpuart_txdma_ops, +# else + .ops = &g_lpuart_ops, +# endif + }, + + .uartbase = NXXX_LPUART3_BASE, + .uartnum = 3, + .baud = CONFIG_LPUART3_BAUD, + .irq = NXXX_IRQ_LP_FLEXCOMM3, + .parity = CONFIG_LPUART3_PARITY, + .bits = CONFIG_LPUART3_BITS, + .lock = SP_UNLOCKED, + .stopbits2 = CONFIG_LPUART3_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART3_OFLOWCONTROL) + .usects = true, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART3_IFLOWCONTROL) + .userts = true, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART3_INVERTIFLOWCONTROL) + .inviflow = true, +# endif + +# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART3_RS485RTSCONTROL) + .rs485mode = true, +# endif + +# ifdef CONFIG_LPUART3_TXDMA + .txch = DMA_REQUEST_MUXLPUART3TX, +# endif +# ifdef CONFIG_LPUART3_RXDMA + .rxch = DMA_REQUEST_MUXLPUART3RX, + .rxfifo = g_lpuart3rxfifo, +# endif +}; +#endif + +#ifdef CONFIG_NXXX_LPUART4 +static struct nxxx_uart_s g_lpuart4priv = +{ + .dev = + { + .recv = + { + .size = CONFIG_LPUART4_RXBUFSIZE, + .buffer = g_lpuart4rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART4_TXBUFSIZE, + .buffer = g_lpuart4txbuffer, + }, +# if defined(CONFIG_LPUART4_RXDMA) && defined(CONFIG_LPUART4_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, +# elif defined(CONFIG_LPUART4_RXDMA) && !defined(CONFIG_LPUART4_TXDMA) + .ops = &g_lpuart_rxdma_ops, +# elif !defined(CONFIG_LPUART4_RXDMA) && defined(CONFIG_LPUART4_TXDMA) + .ops = &g_lpuart_txdma_ops, +# else + .ops = &g_lpuart_ops, +# endif + }, + + .uartbase = NXXX_LPUART4_BASE, + .uartnum = 4, + .baud = CONFIG_LPUART4_BAUD, + .irq = NXXX_IRQ_LP_FLEXCOMM4, + .parity = CONFIG_LPUART4_PARITY, + .bits = CONFIG_LPUART4_BITS, + .lock = SP_UNLOCKED, + .stopbits2 = CONFIG_LPUART4_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART4_OFLOWCONTROL) + .usects = true, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART4_IFLOWCONTROL) + .userts = true, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART4_INVERTIFLOWCONTROL) + .inviflow = true, +# endif + +# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART4_RS485RTSCONTROL) + .rs485mode = true, +# endif + +# ifdef CONFIG_LPUART4_TXDMA + .txch = DMA_REQUEST_MUXLPUART4TX, +# endif +# ifdef CONFIG_LPUART4_RXDMA + .rxch = DMA_REQUEST_MUXLPUART4RX, + .rxfifo = g_lpuart4rxfifo, +# endif +}; +#endif + +#ifdef CONFIG_NXXX_LPUART5 +static struct nxxx_uart_s g_lpuart5priv = +{ + .dev = + { + .recv = + { + .size = CONFIG_LPUART5_RXBUFSIZE, + .buffer = g_lpuart5rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART5_TXBUFSIZE, + .buffer = g_lpuart5txbuffer, + }, +# if defined(CONFIG_LPUART5_RXDMA) && defined(CONFIG_LPUART5_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, +# elif defined(CONFIG_LPUART5_RXDMA) && !defined(CONFIG_LPUART5_TXDMA) + .ops = &g_lpuart_rxdma_ops, +# elif !defined(CONFIG_LPUART5_RXDMA) && defined(CONFIG_LPUART5_TXDMA) + .ops = &g_lpuart_txdma_ops, +# else + .ops = &g_lpuart_ops, +# endif + }, + + .uartbase = NXXX_LPUART5_BASE, + .uartnum = 5, + .baud = CONFIG_LPUART5_BAUD, + .irq = NXXX_IRQ_LP_FLEXCOMM5, + .parity = CONFIG_LPUART5_PARITY, + .bits = CONFIG_LPUART5_BITS, + .lock = SP_UNLOCKED, + .stopbits2 = CONFIG_LPUART5_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART5_OFLOWCONTROL) + .usects = true, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART5_IFLOWCONTROL) + .userts = true, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART5_INVERTIFLOWCONTROL) + .inviflow = true, +# endif + +# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART5_RS485RTSCONTROL) + .rs485mode = true, +# endif + +# ifdef CONFIG_LPUART5_TXDMA + .txch = DMA_REQUEST_MUXLPUART5TX, +# endif +# ifdef CONFIG_LPUART5_RXDMA + .rxch = DMA_REQUEST_MUXLPUART5RX, + .rxfifo = g_lpuart5rxfifo, +# endif +}; +#endif + +#ifdef CONFIG_NXXX_LPUART6 +static struct nxxx_uart_s g_lpuart6priv = +{ + .dev = + { + .recv = + { + .size = CONFIG_LPUART6_RXBUFSIZE, + .buffer = g_lpuart6rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART6_TXBUFSIZE, + .buffer = g_lpuart6txbuffer, + }, +# if defined(CONFIG_LPUART6_RXDMA) && defined(CONFIG_LPUART6_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, +# elif defined(CONFIG_LPUART6_RXDMA) && !defined(CONFIG_LPUART6_TXDMA) + .ops = &g_lpuart_rxdma_ops, +# elif !defined(CONFIG_LPUART6_RXDMA) && defined(CONFIG_LPUART6_TXDMA) + .ops = &g_lpuart_txdma_ops, +# else + .ops = &g_lpuart_ops, +# endif + }, + + .uartbase = NXXX_LPUART6_BASE, + .uartnum = 6, + .baud = CONFIG_LPUART6_BAUD, + .irq = NXXX_IRQ_LP_FLEXCOMM6, + .parity = CONFIG_LPUART6_PARITY, + .bits = CONFIG_LPUART6_BITS, + .lock = SP_UNLOCKED, + .stopbits2 = CONFIG_LPUART6_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART6_OFLOWCONTROL) + .usects = true, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART6_IFLOWCONTROL) + .userts = true, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART6_INVERTIFLOWCONTROL) + .inviflow = true, +# endif + +# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART6_RS485RTSCONTROL) + .rs485mode = true, +# endif + +# ifdef CONFIG_LPUART6_TXDMA + .txch = DMA_REQUEST_MUXLPUART6TX, +# endif +# ifdef CONFIG_LPUART6_RXDMA + .rxch = DMA_REQUEST_MUXLPUART6RX, + .rxfifo = g_lpuart6rxfifo, +# endif +}; +#endif + +#ifdef CONFIG_NXXX_LPUART7 +static struct nxxx_uart_s g_lpuart7priv = +{ + .dev = + { + .recv = + { + .size = CONFIG_LPUART7_RXBUFSIZE, + .buffer = g_lpuart7rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART7_TXBUFSIZE, + .buffer = g_lpuart7txbuffer, + }, +# if defined(CONFIG_LPUART7_RXDMA) && defined(CONFIG_LPUART7_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, +# elif defined(CONFIG_LPUART7_RXDMA) && !defined(CONFIG_LPUART7_TXDMA) + .ops = &g_lpuart_rxdma_ops, +# elif !defined(CONFIG_LPUART7_RXDMA) && defined(CONFIG_LPUART7_TXDMA) + .ops = &g_lpuart_txdma_ops, +# else + .ops = &g_lpuart_ops, +# endif + }, + + .uartbase = NXXX_LPUART7_BASE, + .uartnum = 7, + .baud = CONFIG_LPUART7_BAUD, + .irq = NXXX_IRQ_LP_FLEXCOMM7, + .parity = CONFIG_LPUART7_PARITY, + .bits = CONFIG_LPUART7_BITS, + .lock = SP_UNLOCKED, + .stopbits2 = CONFIG_LPUART7_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART7_OFLOWCONTROL) + .usects = true, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART7_IFLOWCONTROL) + .userts = true, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART7_INVERTIFLOWCONTROL) + .inviflow = true, +# endif + +# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART7_RS485RTSCONTROL) + .rs485mode = true, +# endif + +# ifdef CONFIG_LPUART7_TXDMA + .txch = DMA_REQUEST_MUXLPUART7TX, +# endif +# ifdef CONFIG_LPUART7_RXDMA + .rxch = DMA_REQUEST_MUXLPUART7RX, + .rxfifo = g_lpuart7rxfifo, +# endif +}; +#endif + +#ifdef CONFIG_PM +static struct pm_callback_s g_serial_pmcb = +{ + .notify = up_pm_notify, + .prepare = up_pm_prepare, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxxx_serialin + ****************************************************************************/ + +static inline uint32_t nxxx_serialin(struct nxxx_uart_s *priv, + uint32_t offset) +{ + return getreg32(priv->uartbase + offset); +} + +/**************************************************************************** + * Name: nxxx_serialout + ****************************************************************************/ + +static inline void nxxx_serialout(struct nxxx_uart_s *priv, + uint32_t offset, uint32_t value) +{ + putreg32(value, priv->uartbase + offset); +} + +/**************************************************************************** + * Name: nxxx_dma_nextrx + * + * Description: + * Returns the index into the RX FIFO where the DMA will place the next + * byte that it receives. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static int nxxx_dma_nextrx(struct nxxx_uart_s *priv) +{ + int dmaresidual = nxxx_dmach_getcount(priv->rxdma); + DEBUGASSERT(dmaresidual <= RXDMA_BUFFER_SIZE); + + return (RXDMA_BUFFER_SIZE - dmaresidual) % RXDMA_BUFFER_SIZE; +} +#endif + +/**************************************************************************** + * Name: nxxx_disableuartint + ****************************************************************************/ + +static inline void nxxx_disableuartint_nolock(struct nxxx_uart_s *priv, + uint32_t *ie) +{ + uint32_t regval; + + regval = nxxx_serialin(priv, NXXX_LPUART_CTRL_OFFSET); + + /* Return the current Rx and Tx interrupt state */ + + if (ie != NULL) + { + *ie = regval & LPUART_ALL_INTS; + } + + regval &= ~LPUART_ALL_INTS; + nxxx_serialout(priv, NXXX_LPUART_CTRL_OFFSET, regval); +} + +static inline void nxxx_disableuartint(struct nxxx_uart_s *priv, + uint32_t *ie) +{ + irqstate_t flags; + + flags = spin_lock_irqsave(&priv->lock); + nxxx_disableuartint_nolock(priv, ie); + spin_unlock_irqrestore(&priv->lock, flags); +} + +/**************************************************************************** + * Name: nxxx_restoreuartint + ****************************************************************************/ + +static inline void nxxx_restoreuartint_nolock(struct nxxx_uart_s *priv, + uint32_t ie) +{ + uint32_t regval; + + regval = nxxx_serialin(priv, NXXX_LPUART_CTRL_OFFSET); + regval &= ~LPUART_ALL_INTS; + regval |= ie; + nxxx_serialout(priv, NXXX_LPUART_CTRL_OFFSET, regval); +} + +static inline void nxxx_restoreuartint(struct nxxx_uart_s *priv, + uint32_t ie) +{ + irqstate_t flags; + + /* Enable/disable any interrupts that are currently disabled but should be + * enabled/disabled. + */ + + flags = spin_lock_irqsave(&priv->lock); + nxxx_restoreuartint_nolock(priv, ie); + spin_unlock_irqrestore(&priv->lock, flags); +} + +/**************************************************************************** + * Name: nxxx_dma_setup + * + * Description: + * Configure the LPUART baud, bits, parity, etc. This method is called the + * first time that the serial port is opened. + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) +static int nxxx_dma_setup(struct uart_dev_s *dev) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; +#if defined(SERIAL_HAVE_RXDMA) + struct nxxx_edma_xfrconfig_s config; +#endif + int result; + + /* Do the basic UART setup first, unless we are the console */ + + if (!dev->isconsole) + { + result = nxxx_setup(dev); + if (result != OK) + { + return result; + } + } + +#if defined(SERIAL_HAVE_TXDMA) + /* Acquire the Tx DMA channel. This should always succeed. */ + + if (priv->txch != 0) + { + if (priv->txdma == NULL) + { + priv->txdma = nxxx_dmach_alloc(priv->txch, 0); + if (priv->txdma == NULL) + { + return -EBUSY; + } + } + + /* Enable Tx DMA for the UART */ + + modifyreg32(priv->uartbase + NXXX_LPUART_BAUD_OFFSET, + 0, LPUART_BAUD_TDMAE); + } +#endif + +#if defined(SERIAL_HAVE_RXDMA) + /* Acquire the Rx DMA channel. This should always succeed. */ + + if (priv->rxch != 0) + { + if (priv->rxdma == NULL) + { + priv->rxdma = nxxx_dmach_alloc(priv->rxch, 0); + + if (priv->rxdma == NULL) + { + return -EBUSY; + } + } + else + { + nxxx_dmach_stop(priv->rxdma); + } + + /* Configure for circular DMA reception into the RX FIFO */ + + config.saddr = priv->uartbase + NXXX_LPUART_DATA_OFFSET; + config.daddr = (uintptr_t)priv->rxfifo; + config.soff = 0; + config.doff = 1; + config.iter = RXDMA_BUFFER_SIZE; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE | + EDMA_CONFIG_LOOPDEST | + EDMA_CONFIG_INTHALF | + EDMA_CONFIG_INTMAJOR; + config.ssize = EDMA_8BIT; + config.dsize = EDMA_8BIT; + config.nbytes = 1; +#ifdef CONFIG_NXXX_EDMA_ELINK + config.linkch = 0; +#endif + + nxxx_dmach_xfrsetup(priv->rxdma , &config); + + /* Reset our DMA shadow pointer and Rx data availability count to + * match the address just programmed above. + */ + + priv->rxdmanext = 0; + +#ifndef CONFIG_ARM64_DCACHE_DISABLE + + /* Make sure the rx buffer area is all invalid or clean */ + + up_invalidate_dcache((uintptr_t)priv->rxfifo, + (uintptr_t)priv->rxfifo + RXDMA_BUFFER_SIZE); + priv->rxdmaavail = 0; +#endif + + /* Enable receive Rx DMA for the UART */ + + modifyreg32(priv->uartbase + NXXX_LPUART_BAUD_OFFSET, + 0, LPUART_BAUD_RDMAE); + + /* Enable interrupt on idle and erros */ + + modifyreg32(priv->uartbase + NXXX_LPUART_CTRL_OFFSET, 0, + LPUART_CTRL_PEIE | + LPUART_CTRL_FEIE | + LPUART_CTRL_NEIE | + LPUART_CTRL_ILIE); + + /* Start the DMA channel, and arrange for callbacks at the half and + * full points in the FIFO. This ensures that we have half a FIFO + * worth of time to claim bytes before they are overwritten. + */ + + nxxx_dmach_start(priv->rxdma, nxxx_dma_rxcallback, (void *)priv); + } +#endif + + return OK; +} +#endif + +/**************************************************************************** + * Name: nxxx_setup + * + * Description: + * Configure the UART baud, bits, parity, fifos, etc. This + * method is called the first time that the serial priv is + * opened. + * + ****************************************************************************/ + +static int nxxx_setup(struct uart_dev_s *dev) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; +#ifndef CONFIG_SUPPRESS_LPUART_CONFIG + struct uart_config_s config; + int ret; + + /* Configure the UART */ + + memset(&config, 0, sizeof(config)); + config.baud = priv->baud; /* Configured baud */ + config.parity = priv->parity; /* 0=none, 1=odd, 2=even */ + config.bits = priv->bits; /* Number of bits (5-9) */ + config.stopbits2 = priv->stopbits2; /* true: Configure with 2 stop bits instead of 1 */ + + config.users485 = priv->rs485mode; /* Switch into RS485 mode */ + config.userts = priv->iflow; + config.invrts = priv->inviflow; /* Inversion of outbound flow control */ + config.usects = priv->oflow; + + ret = nxxx_lpuart_configure(priv->uartbase, priv->uartnum, &config); + + priv->ie = nxxx_serialin(priv, NXXX_LPUART_CTRL_OFFSET) & \ + LPUART_ALL_INTS; + return ret; + +#else + priv->ie = nxxx_serialin(priv, NXXX_LPUART_CTRL_OFFSET) & \ + LPUART_ALL_INTS; + return OK; +#endif +} + +/**************************************************************************** + * Name: nxxx_shutdown + * + * Description: + * Disable the UART. This method is called when the serial + * priv is closed + * + ****************************************************************************/ + +static void nxxx_shutdown(struct uart_dev_s *dev) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + + /* Disable the UART */ + + nxxx_serialout(priv, NXXX_LPUART_GLOBAL_OFFSET, LPUART_GLOBAL_RST); +} + +/**************************************************************************** + * Name: nxxx_dma_shutdown + * + * Description: + * Disable the LPUART. This method is called when the serial + * port is closed + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) +static void nxxx_dma_shutdown(struct uart_dev_s *dev) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + + /* Perform the normal UART shutdown */ + + nxxx_shutdown(dev); + +#if defined(SERIAL_HAVE_RXDMA) + /* Stop the RX DMA channel */ + + if (priv->rxch != 0) + { + nxxx_dmach_stop(priv->rxdma); + + /* Release the RX DMA channel */ + + nxxx_dmach_free(priv->rxdma); + priv->rxdma = NULL; + } +#endif + +#if defined(SERIAL_HAVE_TXDMA) + /* Stop the TX DMA channel */ + + if (priv->txch != 0) + { + nxxx_dmach_stop(priv->txdma); + + /* Release the TX DMA channel */ + + nxxx_dmach_free(priv->txdma); + priv->txdma = NULL; + } +#endif +} +#endif + +/**************************************************************************** + * Name: nxxx_attach + * + * Description: + * Configure the UART to operation in interrupt driven mode. This method + * is called when the serial priv is opened. Normally, this is just after + * the setup() method is called, however, the serial console may operate + * in a non-interrupt driven mode during the boot phase. + * + * RX and TX interrupts are not enabled when by the attach method (unless + * the hardware supprivs multiple levels of interrupt enabling). The RX + * and TX interrupts are not enabled until the txint() and rxint() methods + * are called. + * + ****************************************************************************/ + +static int nxxx_attach(struct uart_dev_s *dev) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + int ret; + + /* Attach and enable the IRQ */ + + ret = irq_attach(priv->irq, nxxx_interrupt, dev); + if (ret == OK) + { + /* Enable the interrupt (RX and TX interrupts are still disabled + * in the UART + */ + + up_enable_irq(priv->irq); + } + + return ret; +} + +/**************************************************************************** + * Name: nxxx_detach + * + * Description: + * Detach UART interrupts. This method is called when the serial priv is + * closed normally just before the shutdown method is called. The + * exception is the serial console which is never shutdown. + * + ****************************************************************************/ + +static void nxxx_detach(struct uart_dev_s *dev) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + + up_disable_irq(priv->irq); + irq_detach(priv->irq); +} + +/**************************************************************************** + * Name: nxxx_interrupt (and front-ends) + * + * Description: + * This is the common UART interrupt handler. It will be invoked when an + * interrupt is received on the 'irq'. It should call uart_xmitchars or + * uart_recvchars to perform the appropriate data transfers. The + * interrupt handling logic must be able to map the 'arg' to the + * appropriate uart_dev_s structure in order to call these functions. + * + ****************************************************************************/ + +static int nxxx_interrupt(int irq, void *context, void *arg) +{ + struct uart_dev_s *dev = (struct uart_dev_s *)arg; + struct nxxx_uart_s *priv; + uint32_t usr; + uint32_t lsr; + + DEBUGASSERT(dev != NULL && dev != NULL); + priv = (struct nxxx_uart_s *)dev; + +#if defined(CONFIG_PM) && CONFIG_NXXX_PM_SERIAL_ACTIVITY > 0 + /* Repriv serial activity to the power management logic */ + + pm_activity(PM_IDLE_DOMAIN, CONFIG_NXXX_PM_SERIAL_ACTIVITY); +#endif + + /* Get the current UART status and check for loop + * termination conditions + */ + + usr = nxxx_serialin(priv, NXXX_LPUART_STAT_OFFSET); + + /* Removed all W1C from the last sr */ + + lsr = usr & ~(LPUART_STAT_LBKDIF | LPUART_STAT_RXEDGIF | + LPUART_STAT_IDLE | LPUART_STAT_OR | + LPUART_STAT_NF | LPUART_STAT_FE | + LPUART_STAT_PF | LPUART_STAT_MA1F | + LPUART_STAT_MA2F); + + /* Keep what we will service */ + + usr &= (LPUART_STAT_RDRF | LPUART_STAT_TDRE | LPUART_STAT_OR | + LPUART_STAT_FE | LPUART_STAT_NF | LPUART_STAT_PF | + LPUART_STAT_IDLE); + + /* Clear serial overrun, parity and framing errors */ + + if ((usr & LPUART_STAT_OR) != 0) + { + nxxx_serialout(priv, NXXX_LPUART_STAT_OFFSET, + LPUART_STAT_OR | lsr); + } + + if ((usr & LPUART_STAT_NF) != 0) + { + nxxx_serialout(priv, NXXX_LPUART_STAT_OFFSET, + LPUART_STAT_NF | lsr); + } + + if ((usr & LPUART_STAT_PF) != 0) + { + nxxx_serialout(priv, NXXX_LPUART_STAT_OFFSET, + LPUART_STAT_PF | lsr); + } + + if ((usr & LPUART_STAT_FE) != 0) + { + nxxx_serialout(priv, NXXX_LPUART_STAT_OFFSET, + LPUART_STAT_FE | lsr); + } + + if ((usr & (LPUART_STAT_FE | LPUART_STAT_PF | LPUART_STAT_NF)) != 0) + { + /* Discard data */ + + nxxx_serialin(priv, NXXX_LPUART_DATA_OFFSET); + } + +#ifdef SERIAL_HAVE_RXDMA + /* The line going to idle, deliver any fractions of RX data */ + + if ((usr & LPUART_STAT_IDLE) != 0) + { + nxxx_serialout(priv, NXXX_LPUART_STAT_OFFSET, + LPUART_STAT_IDLE | lsr); + nxxx_dma_rxcallback(priv->rxdma, priv, false, LPUART_STAT_IDLE); + } +#endif + + /* Handle incoming, receive bytes */ + + if ((priv->ie & LPUART_CTRL_RIE) != 0 && nxxx_rxavailable(&priv->dev)) + { + uart_recvchars(dev); + } + + /* Handle outgoing, transmit bytes */ + + if ((priv->ie & LPUART_CTRL_TIE) != 0) + { + uart_xmitchars(dev); + } + + return OK; +} + +/**************************************************************************** + * Name: nxxx_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * + ****************************************************************************/ + +static int nxxx_ioctl(struct file *filep, int cmd, unsigned long arg) +{ +#if defined(CONFIG_SERIAL_TIOCSERGSTRUCT) || \ + defined(CONFIG_SERIAL_TERMIOS) || \ + defined(CONFIG_NXXX_LPUART_SINGLEWIRE ) || \ + defined(CONFIG_NXXX_LPUART_INVERT ) + struct inode *inode = filep->f_inode; + struct uart_dev_s *dev = inode->i_private; + irqstate_t flags; +#endif + int ret = OK; + + switch (cmd) + { +#ifdef CONFIG_SERIAL_TIOCSERGSTRUCT + case TIOCSERGSTRUCT: + { + struct nxxx_uart_s *user = (struct nxxx_uart_s *)arg; + if (!user) + { + ret = -EINVAL; + } + else + { + memcpy(user, dev, sizeof(struct nxxx_uart_s)); + } + } + break; +#endif + +#ifdef CONFIG_SERIAL_TERMIOS + case TCGETS: + { + struct termios *termiosp = (struct termios *)arg; + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + + if (!termiosp) + { + ret = -EINVAL; + break; + } + + /* Return parity */ + + termiosp->c_cflag = ((priv->parity != 0) ? PARENB : 0) | + ((priv->parity == 1) ? PARODD : 0); + + /* Return stop bits */ + + termiosp->c_cflag |= priv->stopbits2 ? CSTOPB : 0; + + /* Return flow control */ + +#ifdef CONFIG_SERIAL_OFLOWCONTROL + termiosp->c_cflag |= (priv->oflow ? CCTS_OFLOW : 0); + +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + termiosp->c_cflag |= (priv->iflow ? CRTS_IFLOW : 0); +#endif + /* Return baud */ + + cfsetispeed(termiosp, priv->baud); + + /* Return number of bits */ + + switch (priv->bits) + { + case 5: + termiosp->c_cflag |= CS5; + break; + + case 6: + termiosp->c_cflag |= CS6; + break; + + case 7: + termiosp->c_cflag |= CS7; + break; + + default: + case 8: + termiosp->c_cflag |= CS8; + break; + +#if defined(CS9) + case 9: + termiosp->c_cflag |= CS9; + break; +#endif + } + } + break; + + case TCSETS: + { + struct termios *termiosp = (struct termios *)arg; + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + uint32_t baud; + uint32_t ie; + uint8_t parity; + uint8_t nbits; + bool stop2; + + if ((!termiosp) +#ifdef CONFIG_SERIAL_OFLOWCONTROL + || ((termiosp->c_cflag & CCTS_OFLOW) && !priv->usects) +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + || ((termiosp->c_cflag & CRTS_IFLOW) && !priv->userts) +#endif + ) + { + ret = -EINVAL; + break; + } + + /* Decode baud. */ + + ret = OK; + baud = cfgetispeed(termiosp); + + /* Decode number of bits */ + + switch (termiosp->c_cflag & CSIZE) + { + case CS5: + nbits = 5; + break; + + case CS6: + nbits = 6; + break; + + case CS7: + nbits = 7; + break; + + case CS8: + nbits = 8; + break; + +#if defined(CS9) + case CS9: + nbits = 9; + break; +#endif + default: + ret = -EINVAL; + break; + } + + /* Decode parity */ + + if ((termiosp->c_cflag & PARENB) != 0) + { + parity = (termiosp->c_cflag & PARODD) ? 1 : 2; + } + else + { + parity = 0; + } + + /* Decode stop bits */ + + stop2 = (termiosp->c_cflag & CSTOPB) != 0; + + /* Verify that all settings are valid before committing */ + + if (ret == OK) + { + /* Commit */ + + priv->baud = baud; + priv->parity = parity; + priv->bits = nbits; + priv->stopbits2 = stop2; + priv->oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0; + priv->iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0; + + /* effect the changes immediately - note that we do not + * implement TCSADRAIN / TCSAFLUSH + */ + + flags = spin_lock_irqsave(&priv->lock); + nxxx_disableuartint_nolock(priv, &ie); + ret = dev->ops->setup(dev); + + /* Restore the interrupt state */ + + nxxx_restoreuartint_nolock(priv, ie); + priv->ie = ie; + spin_unlock_irqrestore(&priv->lock, flags); + } + } + break; +#endif /* CONFIG_SERIAL_TERMIOS */ + +#ifdef CONFIG_NXXX_LPUART_SINGLEWIRE + case TIOCSSINGLEWIRE: + { + uint32_t regval; + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + + flags = spin_lock_irqsave(&priv->lock); + regval = nxxx_serialin(priv, NXXX_LPUART_CTRL_OFFSET); + + if ((arg & SER_SINGLEWIRE_ENABLED) != 0) + { + regval |= LPUART_CTRL_LOOPS | LPUART_CTRL_RSRC; + } + else + { + regval &= ~(LPUART_CTRL_LOOPS | LPUART_CTRL_RSRC); + } + + nxxx_serialout(priv, NXXX_LPUART_CTRL_OFFSET, regval); + + spin_unlock_irqrestore(&priv->lock, flags); + } + break; +#endif + +#ifdef CONFIG_NXXX_LPUART_INVERT + case TIOCSINVERT: + { + uint32_t ctrl; + uint32_t stat; + uint32_t regval; + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + + flags = spin_lock_irqsave(&priv->lock); + ctrl = nxxx_serialin(priv, NXXX_LPUART_CTRL_OFFSET); + stat = nxxx_serialin(priv, NXXX_LPUART_STAT_OFFSET); + regval = ctrl; + + /* {R|T}XINV bit field can only be written when the receiver is + * disabled (RE=0). + */ + + regval &= ~LPUART_CTRL_RE; + + nxxx_serialout(priv, NXXX_LPUART_CTRL_OFFSET, regval); + + /* Enable/disable signal inversion. */ + + if (arg & SER_INVERT_ENABLED_RX) + { + stat |= LPUART_STAT_RXINV; + } + else + { + stat &= ~LPUART_STAT_RXINV; + } + + /* Do not invert TX when in TIOCSSINGLEWIRE */ + + if ((arg & SER_INVERT_ENABLED_TX) && + ((ctrl & LPUART_CTRL_LOOPS) != LPUART_CTRL_LOOPS)) + { + ctrl |= LPUART_CTRL_TXINV; + } + else + { + ctrl &= ~LPUART_CTRL_TXINV; + } + + nxxx_serialout(priv, NXXX_LPUART_STAT_OFFSET, stat); + nxxx_serialout(priv, NXXX_LPUART_CTRL_OFFSET, ctrl); + + spin_unlock_irqrestore(&priv->lock, flags); + } + break; +#endif + + case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ + case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: nxxx_receive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the UART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +#ifndef SERIAL_HAVE_ONLY_RXDMA +static int nxxx_receive(struct uart_dev_s *dev, unsigned int *status) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + uint32_t rxd; + + rxd = nxxx_serialin(priv, NXXX_LPUART_DATA_OFFSET); + *status = rxd >> LPUART_DATA_STATUS_SHIFT; + return (rxd & LPUART_DATA_MASK) >> LPUART_DATA_SHIFT; +} +#endif + +/**************************************************************************** + * Name: nxxx_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +#ifndef SERIAL_HAVE_ONLY_RXDMA +static void nxxx_rxint(struct uart_dev_s *dev, bool enable) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + irqstate_t flags; + uint32_t regval; + + /* Enable interrupts for data available at Rx */ + + flags = spin_lock_irqsave(&priv->lock); + if (enable) + { +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + priv->ie |= LPUART_CTRL_RIE | LPUART_CTRL_FEIE | LPUART_CTRL_ORIE; +#endif + } + else + { + priv->ie &= ~(LPUART_CTRL_RIE | LPUART_CTRL_FEIE | LPUART_CTRL_ORIE); + } + + regval = nxxx_serialin(priv, NXXX_LPUART_CTRL_OFFSET); + regval &= ~LPUART_ALL_INTS; + regval |= priv->ie; + nxxx_serialout(priv, NXXX_LPUART_CTRL_OFFSET, regval); + spin_unlock_irqrestore(&priv->lock, flags); +} +#endif + +/**************************************************************************** + * Name: nxxx_rxavailable + * + * Description: + * Return true if the receive fifo is not empty + * + ****************************************************************************/ + +#ifndef SERIAL_HAVE_ONLY_RXDMA +static bool nxxx_rxavailable(struct uart_dev_s *dev) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + uint32_t regval; + + /* Return true is data is ready in the Rx FIFO */ + + regval = nxxx_serialin(priv, NXXX_LPUART_WATER_OFFSET); + return ((regval & LPUART_WATER_RXCOUNT_MASK) != 0); +} +#endif + +/**************************************************************************** + * Name: nxxx_dma_receive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the LPUART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static int nxxx_dma_receive(struct uart_dev_s *dev, unsigned int *status) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + uint32_t nextrx = nxxx_dma_nextrx(priv); + int c = 0; + + /* Check if more data is available */ + + if (nextrx != priv->rxdmanext) + { +#ifndef CONFIG_ARM64_DCACHE_DISABLE + /* If the data cache is enabled, then we will also need to manage + * cache coherency. Are any bytes available in the currently coherent + * region of the data cache? + */ + + if (priv->rxdmaavail == 0) + { + uint32_t rxdmaavail; + uintptr_t addr; + + /* No.. then we will have to invalidate additional space in the Rx + * DMA buffer. + */ + + if (nextrx > priv->rxdmanext) + { + /* Number of available bytes */ + + rxdmaavail = nextrx - priv->rxdmanext; + } + else + { + /* Number of available bytes up to the end of RXDMA buffer */ + + rxdmaavail = RXDMA_BUFFER_SIZE - priv->rxdmanext; + } + + /* Invalidate the DMA buffer range */ + + addr = (uintptr_t)&priv->rxfifo[priv->rxdmanext]; + up_invalidate_dcache(addr, addr + rxdmaavail); + + /* We don't need to invalidate the data cache for the next + * rxdmaavail number of next bytes. + */ + + priv->rxdmaavail = rxdmaavail; + } + + priv->rxdmaavail--; +#endif + + /* Now read from the DMA buffer */ + + c = priv->rxfifo[priv->rxdmanext]; + + priv->rxdmanext++; + + if (priv->rxdmanext == RXDMA_BUFFER_SIZE) + { + priv->rxdmanext = 0; + } + } + + /* NOTE: If no data is available, then we would return NULL which is, + * of course, valid binary data. The protocol is that the upper half + * driver must call nxxx_dma_rxavailable prior to calling this + * function to assure that this never happens. + */ + + return c; +} +#endif + +/**************************************************************************** + * Name: nxxx_dma_reenable + * + * Description: + * Call to re-enable RX DMA. + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) && defined(CONFIG_PM) +static void nxxx_dma_reenable(struct nxxx_uart_s *priv) +{ + struct nxxx_edma_xfrconfig_s config; + + /* Stop an reset the RX DMA */ + + nxxx_dmach_stop(priv->rxdma); + + /* Configure for circular DMA reception into the RX FIFO */ + + config.saddr = priv->uartbase + NXXX_LPUART_DATA_OFFSET; + config.daddr = (uint32_t) priv->rxfifo; + config.soff = 0; + config.doff = 1; + config.iter = RXDMA_BUFFER_SIZE; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE | + EDMA_CONFIG_LOOPDEST | + EDMA_CONFIG_INTHALF | + EDMA_CONFIG_INTMAJOR; + config.ssize = EDMA_8BIT; + config.dsize = EDMA_8BIT; + config.nbytes = 1; +#ifdef CONFIG_NXXX_EDMA_ELINK + config.linkch = 0; +#endif + + nxxx_dmach_xfrsetup(priv->rxdma, &config); + + /* Reset our DMA shadow pointer and Rx data availability count to match + * the address just programmed above. + */ + + priv->rxdmanext = 0; +#ifndef CONFIG_ARM64_DCACHE_DISABLE + priv->rxdmaavail = 0; +#endif + + /* Start the DMA channel, and arrange for callbacks at the half and + * full points in the FIFO. This ensures that we have half a FIFO + * worth of time to claim bytes before they are overwritten. + */ + + nxxx_dmach_start(priv->rxdma, nxxx_dma_rxcallback, (void *)priv); + + /* Clear DMA suspended flag. */ + + priv->rxdmasusp = false; +} +#endif + +/**************************************************************************** + * Name: nxxx_dma_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static void nxxx_dma_rxint(struct uart_dev_s *dev, bool enable) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + + /* Enable/disable DMA reception. + * + * Note that it is not safe to check for available bytes and immediately + * pass them to uart_recvchars as that could potentially recurse back + * to us again. Instead, bytes must wait until the next up_dma_poll or + * DMA event. + */ + + priv->rxenable = enable; +} +#endif + +/**************************************************************************** + * Name: nxxx_dma_rxavailable + * + * Description: + * Return true if the receive register is not empty + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static bool nxxx_dma_rxavailable(struct uart_dev_s *dev) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + + /* Compare our receive pointer to the current DMA pointer, if they + * do not match, then there are bytes to be received. + */ + + return (nxxx_dma_nextrx(priv) != priv->rxdmanext); +} +#endif + +/**************************************************************************** + * Name: nxxx_dma_txcallback + * + * Description: + * This function clears dma buffer at complete of DMA transfer and wakes up + * threads waiting for space in buffer. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void nxxx_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done, + int result) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)arg; + + /* Update 'nbytes' indicating number of bytes actually transferred by DMA. + * This is important to free TX buffer space by 'uart_xmitchars_done'. + */ + + priv->dev.dmatx.nbytes = priv->dev.dmatx.length; +#if CONFIG_NXXX_EDMA_NTCD > 1 + priv->dev.dmatx.nbytes += priv->dev.dmatx.nlength; +#endif + + /* Adjust the pointers */ + + uart_xmitchars_done(&priv->dev); + + /* Send more data if available */ + + nxxx_dma_txavailable(&priv->dev); +} +#endif + +/**************************************************************************** + * Name: nxxx_dma_txavailable + * + * Description: + * Informs DMA that Tx data is available and is ready for transfer. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void nxxx_dma_txavailable(struct uart_dev_s *dev) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + + /* Only send when the DMA is idle */ + + if (nxxx_dmach_idle(priv->txdma) == 0) + { + uart_xmitchars_dma(dev); + } +} +#endif + +/**************************************************************************** + * Name: nxxx_dma_send + * + * Description: + * Called (usually) from the interrupt level to start DMA transfer. + * (Re-)Configures DMA Stream updating buffer and buffer length. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void nxxx_dma_send(struct uart_dev_s *dev) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + struct nxxx_edma_xfrconfig_s config; + + /* We need to stop DMA before reconfiguration */ + + nxxx_dmach_stop(priv->txdma); + + /* Reset the number sent */ + + dev->dmatx.nbytes = 0; + + /* Make use of setup function to update buffer and its length for next + * transfer + */ + + config.iter = dev->dmatx.length; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE; + config.ssize = EDMA_8BIT; + config.dsize = EDMA_8BIT; + config.nbytes = 1; + config.saddr = (uintptr_t)dev->dmatx.buffer; + config.daddr = priv->uartbase + NXXX_LPUART_DATA_OFFSET; + config.soff = 1; + config.doff = 0; +#ifdef CONFIG_NXXX_EDMA_ELINK + config.linkch = 0; +#endif + + /* Flush the contents of the TX buffer into physical memory */ + + up_clean_dcache((uintptr_t)dev->dmatx.buffer, + (uintptr_t)dev->dmatx.buffer + dev->dmatx.length); + + /* Setup first half */ + + nxxx_dmach_xfrsetup(priv->txdma, &config); + +#if CONFIG_NXXX_EDMA_NTCD > 1 + /* Is this a split transfer? */ + + if (dev->dmatx.nbuffer) + { + config.iter = priv->dev.dmatx.nlength; + config.saddr = (uintptr_t)priv->dev.dmatx.nbuffer; + + /* Flush the contents of the next TX buffer into physical memory */ + + up_clean_dcache((uintptr_t)dev->dmatx.nbuffer, + (uintptr_t)dev->dmatx.nbuffer + dev->dmatx.nlength); + + nxxx_dmach_xfrsetup(priv->txdma, &config); + } +#endif + + /* Start transmission with the callback on DMA completion */ + + nxxx_dmach_start(priv->txdma, nxxx_dma_txcallback, (void *)priv); +} +#endif + +/**************************************************************************** + * Name: nxxx_send + * + * Description: + * This method will send one byte on the UART + * + ****************************************************************************/ + +static void nxxx_send(struct uart_dev_s *dev, int ch) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + +#ifdef CONSOLE_DEV + if (dev == &CONSOLE_DEV.dev && !dev->isconsole) + { + return; + } +#endif + + nxxx_serialout(priv, NXXX_LPUART_DATA_OFFSET, (uint32_t)ch); +} + +/**************************************************************************** + * Name: nxxx_dma_txint + * + * Description: + * Call to enable or disable TX interrupts from the UART. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void nxxx_dma_txint(struct uart_dev_s *dev, bool enable) +{ + /* Nothing to do. */ + + /* In case of DMA transfer we do not want to make use of UART interrupts. + * Instead, we use DMA interrupts that are activated once during boot + * sequence. Furthermore we can use nxxx_dma_txcallback() to handle + * stuff at half DMA transfer or after transfer completion (depending + * on the configuration). + */ +} +#endif + +/**************************************************************************** + * Name: nxxx_txint + * + * Description: + * Call to enable or disable TX interrupts + * + ****************************************************************************/ + +#if !defined(SERIAL_HAVE_ONLY_TXDMA) +static void nxxx_txint(struct uart_dev_s *dev, bool enable) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + irqstate_t flags; + uint32_t regval; + + /* Enable interrupt for TX complete */ + + flags = spin_lock_irqsave(&priv->lock); + if (enable) + { +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + priv->ie |= LPUART_CTRL_TIE; +#endif + } + else + { + priv->ie &= ~LPUART_CTRL_TIE; + } + + regval = nxxx_serialin(priv, NXXX_LPUART_CTRL_OFFSET); + regval &= ~LPUART_ALL_INTS; + regval |= priv->ie; + nxxx_serialout(priv, NXXX_LPUART_CTRL_OFFSET, regval); + +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + if (enable) + { + uart_xmitchars(dev); + } +#endif + + spin_unlock_irqrestore(&priv->lock, flags); +} +#endif + +/**************************************************************************** + * Name: nxxx_txready + * + * Description: + * Return true if the transmit fifo is available to be written to + * + ****************************************************************************/ + +static bool nxxx_txready(struct uart_dev_s *dev) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + uint32_t regval; + uint32_t fifo_size; + uint32_t fifo_count; + + /* Read the fifo size and current fill ratio. Return true if fifo is not + * full + */ + + regval = nxxx_serialin(priv, NXXX_LPUART_FIFO_OFFSET); + fifo_size = (regval & LPUART_FIFO_TXFIFOSIZE_MASK) >> + LPUART_FIFO_TXFIFOSIZE_SHIFT; + fifo_size = fifo_size == 0 ? 1 : (1 << (fifo_size + 1)); + regval = nxxx_serialin(priv, NXXX_LPUART_WATER_OFFSET); + fifo_count = (regval & LPUART_WATER_TXCOUNT_MASK) >> + LPUART_WATER_TXCOUNT_SHIFT; + + return fifo_count < fifo_size; +} + +/**************************************************************************** + * Name: nxxx_txempty + * + * Description: + * Return true if the transmit fifo is empty + * + ****************************************************************************/ + +static bool nxxx_txempty(struct uart_dev_s *dev) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)dev; + uint32_t regval; + + regval = nxxx_serialin(priv, NXXX_LPUART_WATER_OFFSET); + return (regval & LPUART_WATER_TXCOUNT_MASK) == 0; +} + +/**************************************************************************** + * Name: nxxx_dma_rxcallback + * + * Description: + * This function checks the current DMA state and calls the generic + * serial stack when bytes appear to be available. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static void nxxx_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done, + int result) +{ + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)arg; + uint32_t sr; + + if (priv->rxenable && nxxx_dma_rxavailable(&priv->dev)) + { + uart_recvchars(&priv->dev); + } + + /* Get the masked LPUART status word to check and clear error flags. + * + * When wake-up from low power mode was not fast enough, UART is resumed + * too late and sometimes exactly when character was coming over UART, + * resulting to frame error. + * If error flag is not cleared, Rx DMA will be stuck. Clearing errors + * will release Rx DMA. + */ + + sr = nxxx_serialin(priv, NXXX_LPUART_STAT_OFFSET); + + if ((sr & (LPUART_STAT_OR | LPUART_STAT_NF | LPUART_STAT_FE)) != 0) + { + nxxx_serialout(priv, NXXX_LPUART_STAT_OFFSET, + sr & (LPUART_STAT_OR | + LPUART_STAT_NF | + LPUART_STAT_FE)); + } +} +#endif + +/**************************************************************************** + * Name: up_pm_notify + * + * Description: + * Notify the driver of new power state. This callback is called after + * all drivers have had the opprivunity to prepare for the new power state. + * + * Input Parameters: + * + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state data at + * the end of the structure. + * + * pmstate - Identifies the new PM state + * + * Returned Value: + * None - The driver already agreed to transition to the low power + * consumption state when when it returned OK to the prepare() call. + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static void up_pm_notify(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + switch (pmstate) + { + case(PM_NORMAL): + { + /* Logic for PM_NORMAL goes here */ + } + break; + + case(PM_IDLE): + { + /* Logic for PM_IDLE goes here */ + } + break; + + case(PM_STANDBY): + { + /* Logic for PM_STANDBY goes here */ + } + break; + + case(PM_SLEEP): + { + /* Logic for PM_SLEEP goes here */ + } + break; + + default: + + /* Should not get here */ + + break; + } +} +#endif + +/**************************************************************************** + * Name: up_pm_prepare + * + * Description: + * Request the driver to prepare for a new power state. This is a warning + * that the system is about to enter into a new power state. The driver + * should begin whatever operations that may be required to enter power + * state. The driver may abort the state change mode by returning a + * non-zero value from the callback function. + * + * Input Parameters: + * + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state data at + * the end of the structure. + * + * pmstate - Identifies the new PM state + * + * Returned Value: + * Zero - (OK) means the event was successfully processed and that the + * driver is prepared for the PM state change. + * + * Non-zero - means that the driver is not prepared to perform the tasks + * needed achieve this power setting and will cause the state + * change to be aborted. NOTE: The prepare() method will also + * be called when reverting from lower back to higher power + * consumption modes (say because another driver refused a + * lower power state change). Drivers are not permitted to + * return non-zero values when reverting back to higher power + * consumption modes! + * + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static int up_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + /* Logic to prepare for a reduced power state goes here. */ + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_earlyserialinit + * + * Description: + * Performs the low level UART initialization early in debug so that the + * serial console will be available during bootup. This must be called + * before arm_serialinit. + * + ****************************************************************************/ + +void arm_earlyserialinit(void) +{ + /* NOTE: This function assumes that low level hardware configuration + * -- including all clocking and pin configuration -- was performed by the + * function nxxx_lowsetup() earlier in the boot sequence. + */ + + /* Enable the console UART. The other UARTs will be initialized if and + * when they are first opened. + */ + +#ifdef CONSOLE_DEV + CONSOLE_DEV.dev.isconsole = true; + nxxx_setup(&CONSOLE_DEV.dev); +#endif +} + +/**************************************************************************** + * Name: arm_serialinit + * + * Description: + * Register serial console and serial privs. This assumes + * that nxxx_earlyserialinit was called previously. + * + ****************************************************************************/ + +void arm_serialinit(void) +{ +#ifdef CONFIG_PM + int ret; + + /* Register to receive power management callbacks */ + + ret = pm_register(&g_serial_pmcb); + DEBUGASSERT(ret == OK); + UNUSED(ret); +#endif + +#ifdef CONSOLE_DEV + uart_register("/dev/console", &CONSOLE_DEV.dev); +#if defined(SERIAL_HAVE_CONSOLE_DMA) + nxxx_dma_setup(&CONSOLE_DEV.dev); +#endif +#endif + + /* Register all UARTs */ + +#ifdef TTYS0_DEV + uart_register("/dev/ttyS0", &TTYS0_DEV.dev); +#endif +#ifdef TTYS1_DEV + uart_register("/dev/ttyS1", &TTYS1_DEV.dev); +#endif +#ifdef TTYS2_DEV + uart_register("/dev/ttyS2", &TTYS2_DEV.dev); +#endif +#ifdef TTYS3_DEV + uart_register("/dev/ttyS3", &TTYS3_DEV.dev); +#endif +#ifdef TTYS4_DEV + uart_register("/dev/ttyS4", &TTYS4_DEV.dev); +#endif +#ifdef TTYS5_DEV + uart_register("/dev/ttyS5", &TTYS5_DEV.dev); +#endif +#ifdef TTYS6_DEV + uart_register("/dev/ttyS6", &TTYS6_DEV.dev); +#endif +#ifdef TTYS7_DEV + uart_register("/dev/ttyS7", &TTYS7_DEV.dev); +#endif +} + +#endif /* USE_SERIALDRIVER */ + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to suppriv OS debug writes + * + ****************************************************************************/ + +void up_putc(int ch) +{ +#ifdef CONSOLE_DEV + struct nxxx_uart_s *priv = (struct nxxx_uart_s *)&CONSOLE_DEV; + uint32_t ie; + + if (!CONSOLE_DEV.dev.isconsole) + { + return; + } + + nxxx_disableuartint(priv, &ie); +#endif + + arm_lowputc(ch); +#ifdef CONSOLE_DEV + nxxx_restoreuartint(priv, ie); +#endif +} diff --git a/arch/arm/src/mcx-nxxx/nxxx_port.c b/arch/arm/src/mcx-nxxx/nxxx_port.c new file mode 100644 index 0000000000000..f1ef7f8fb7979 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/nxxx_port.c @@ -0,0 +1,83 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/nxxx_port.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "chip.h" +#include "nxxx_port.h" +#include "arm_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxxx_port_configure + * + * Description: + * This function writes the PORT configuration for a port.pin pair. + * + * Input Parameters: + * cfg - The PORT configuration + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int nxxx_port_configure(port_cfg_t cfg) +{ + uint32_t regaddr = NXXX_PORT_PCR_BASE(cfg.port, cfg.pin); + putreg32(cfg.cfg, regaddr); + + return OK; +} + +/**************************************************************************** + * Name: nxxx_port_gpio + * + * Description: + * This can be used to forcibly set a port.pin to GPIO mode. This overrides + * and disconnects any peripheral using the pin. + * + * Input Parameters: + * cfg - The PORT configuration. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int nxxx_port_gpio(port_cfg_t cfg) +{ + uint32_t regaddr = NXXX_PORT_PCR_BASE(cfg.port, cfg.pin); + modifyreg32(regaddr, PORT_PCR_MUX_MASK, PORT_PCR_MUX_GPIO); + + return OK; +} diff --git a/arch/arm/src/mcx-nxxx/nxxx_port.h b/arch/arm/src/mcx-nxxx/nxxx_port.h new file mode 100644 index 0000000000000..d23dce88143fb --- /dev/null +++ b/arch/arm/src/mcx-nxxx/nxxx_port.h @@ -0,0 +1,98 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/nxxx_port.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef ARCH_ARM_SRC_MCX_NXXX_NXXX_PORT_H +#define ARCH_ARM_SRC_MCX_NXXX_NXXX_PORT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "hardware/nxxx_port.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PORT_CFG(_port, _pin, _cfg) \ + (struct port_cfg_s) \ + { \ + .port = (_port), \ + .pin = (_pin), \ + .cfg = (_cfg), \ + } + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct port_cfg_s +{ + uint8_t port; + uint8_t pin; + uint16_t cfg; +}; +typedef struct port_cfg_s port_cfg_t; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nxxx_port_configure + * + * Description: + * This function writes the PORT configuration for a port.pin pair. + * + * Input Parameters: + * cfg - The PORT configuration + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int nxxx_port_configure(port_cfg_t cfg); + +/**************************************************************************** + * Name: nxxx_port_gpio + * + * Description: + * This can be used to forcibly set a port.pin to GPIO mode. This overrides + * and disconnects any peripheral using the pin. + * + * Input Parameters: + * cfg - The PORT configuration. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int nxxx_port_gpio(port_cfg_t cfg); + +#endif /* ARCH_ARM_SRC_MCX_NXXX_NXXX_PORT_H */ diff --git a/arch/arm/src/mcx-nxxx/nxxx_serial.h b/arch/arm/src/mcx-nxxx/nxxx_serial.h new file mode 100644 index 0000000000000..15efbbeee7032 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/nxxx_serial.h @@ -0,0 +1,251 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/nxxx_serial.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_MCX_NXXX_NXXX_SERIAL_H +#define __ARCH_ARM_SRC_MCX_NXXX_NXXX_SERIAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_NXXX_LPUART0) || defined(CONFIG_NXXX_LPUART1) || \ + defined(CONFIG_NXXX_LPUART2) || defined(CONFIG_NXXX_LPUART3) || \ + defined(CONFIG_NXXX_LPUART4) || defined(CONFIG_NXXX_LPUART5) || \ + defined(CONFIG_NXXX_LPUART6) || defined(CONFIG_NXXX_LPUART7) +# define HAVE_UART 1 +#endif + +/* Assume DMA is not used on the console UART */ + +#undef SERIAL_HAVE_CONSOLE_RXDMA +#undef SERIAL_HAVE_CONSOLE_TXDMA + +#if !defined(HAVE_UART) || !defined(CONFIG_ARCH_DMA) +# undef CONFIG_LPUART0_RXDMA +# undef CONFIG_LPUART0_TXDMA +# undef CONFIG_LPUART1_RXDMA +# undef CONFIG_LPUART1_TXDMA +# undef CONFIG_LPUART2_RXDMA +# undef CONFIG_LPUART2_TXDMA +# undef CONFIG_LPUART3_RXDMA +# undef CONFIG_LPUART3_TXDMA +# undef CONFIG_LPUART4_RXDMA +# undef CONFIG_LPUART4_TXDMA +# undef CONFIG_LPUART5_RXDMA +# undef CONFIG_LPUART5_TXDMA +# undef CONFIG_LPUART6_RXDMA +# undef CONFIG_LPUART6_TXDMA +# undef CONFIG_LPUART7_RXDMA +# undef CONFIG_LPUART7_TXDMA +#endif + +/* Disable the DMA configuration on all unused LPUARTs */ + +#ifndef CONFIG_NXXX_LPUART0 +# undef CONFIG_LPUART0_RXDMA +# undef CONFIG_LPUART0_TXDMA +#endif + +#ifndef CONFIG_NXXX_LPUART1 +# undef CONFIG_LPUART1_RXDMA +# undef CONFIG_LPUART1_TXDMA +#endif + +#ifndef CONFIG_NXXX_LPUART2 +# undef CONFIG_LPUART2_RXDMA +# undef CONFIG_LPUART2_TXDMA +#endif + +#ifndef CONFIG_NXXX_LPUART3 +# undef CONFIG_LPUART3_RXDMA +# undef CONFIG_LPUART3_TXDMA +#endif + +#ifndef CONFIG_NXXX_LPUART4 +# undef CONFIG_LPUART4_RXDMA +# undef CONFIG_LPUART4_TXDMA +#endif + +#ifndef CONFIG_NXXX_LPUART5 +# undef CONFIG_LPUART5_RXDMA +# undef CONFIG_LPUART5_TXDMA +#endif + +#ifndef CONFIG_NXXX_LPUART6 +# undef CONFIG_LPUART6_RXDMA +# undef CONFIG_LPUART6_TXDMA +#endif + +#ifndef CONFIG_NXXX_LPUART7 +# undef CONFIG_LPUART7_RXDMA +# undef CONFIG_LPUART7_TXDMA +#endif + +/* Is RX DMA available on any (enabled) LPUART? */ + +#undef SERIAL_HAVE_RXDMA +#if defined(CONFIG_LPUART0_RXDMA) || defined(CONFIG_LPUART1_RXDMA) || \ + defined(CONFIG_LPUART2_RXDMA) || defined(CONFIG_LPUART3_RXDMA) || \ + defined(CONFIG_LPUART4_RXDMA) || defined(CONFIG_LPUART5_RXDMA) || \ + defined(CONFIG_LPUART6_RXDMA) || defined(CONFIG_LPUART7_RXDMA) +# define SERIAL_HAVE_RXDMA 1 +#endif + +/* Is TX DMA available on any (enabled) LPUART? */ +#undef SERIAL_HAVE_TXDMA +#if defined(CONFIG_LPUART0_TXDMA) || defined(CONFIG_LPUART1_TXDMA) || \ + defined(CONFIG_LPUART2_TXDMA) || defined(CONFIG_LPUART3_TXDMA) || \ + defined(CONFIG_LPUART4_TXDMA) || defined(CONFIG_LPUART5_TXDMA) || \ + defined(CONFIG_LPUART6_TXDMA) || defined(CONFIG_LPUART7_TXDMA) +# define SERIAL_HAVE_TXDMA 1 +#endif + +/* Is RX DMA used on all (enabled) LPUARTs */ + +#define SERIAL_HAVE_ONLY_RXDMA 1 +#if defined(CONFIG_NXXX_LPUART0) && !defined(CONFIG_LPUART0_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_NXXX_LPUART1) && !defined(CONFIG_LPUART1_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_NXXX_LPUART2) && !defined(CONFIG_LPUART2_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_NXXX_LPUART3) && !defined(CONFIG_LPUART3_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_NXXX_LPUART4) && !defined(CONFIG_LPUART4_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_NXXX_LPUART5) && !defined(CONFIG_LPUART5_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_NXXX_LPUART6) && !defined(CONFIG_LPUART6_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_NXXX_LPUART7) && !defined(CONFIG_LPUART7_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#endif + +/* Is TX DMA used on all (enabled) LPUARTs */ + +#define SERIAL_HAVE_ONLY_TXDMA 1 +#if defined(CONFIG_NXXX_LPUART0) && !defined(CONFIG_LPUART0_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_NXXX_LPUART1) && !defined(CONFIG_LPUART1_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_NXXX_LPUART2) && !defined(CONFIG_LPUART2_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_NXXX_LPUART3) && !defined(CONFIG_LPUART3_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_NXXX_LPUART4) && !defined(CONFIG_LPUART4_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_NXXX_LPUART5) && !defined(CONFIG_LPUART5_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_NXXX_LPUART6) && !defined(CONFIG_LPUART6_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_NXXX_LPUART7) && !defined(CONFIG_LPUART7_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#endif + +#undef SERIAL_HAVE_ONLY_DMA +#if defined(SERIAL_HAVE_ONLY_RXDMA) && defined(SERIAL_HAVE_ONLY_TXDMA) +#define SERIAL_HAVE_ONLY_DMA +#endif + +/* Verify that DMA has been enabled and the DMA channel has been defined. + */ + +#if defined(SERIAL_HAVE_TXDMA) || defined(SERIAL_HAVE_RXDMA) +# ifndef CONFIG_NXXX_EDMA +# error MCX-NXXX LPUART receive or transmit DMA requires CONFIG_NXXX_EDMA +# endif +#endif + +#if defined(SERIAL_HAVE_RXDMA) +/* Currently RS-485 support cannot be enabled when RXDMA is in use due to + * lack of testing. + */ + +# if (defined(CONFIG_LPUART0_RXDMA) && defined(CONFIG_LPUART8_RS485)) || \ + (defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_RS485)) || \ + (defined(CONFIG_LPUART2_RXDMA) && defined(CONFIG_LPUART2_RS485)) || \ + (defined(CONFIG_LPUART3_RXDMA) && defined(CONFIG_LPUART3_RS485)) || \ + (defined(CONFIG_LPUART4_RXDMA) && defined(CONFIG_LPUART4_RS485)) || \ + (defined(CONFIG_LPUART5_RXDMA) && defined(CONFIG_LPUART5_RS485)) || \ + (defined(CONFIG_LPUART6_RXDMA) && defined(CONFIG_LPUART6_RS485)) || \ + (defined(CONFIG_LPUART7_RXDMA) && defined(CONFIG_LPUART7_RS485)) + +# error "RXDMA and RS-485 cannot be enabled at the same time for the same LPUART" +# endif +#endif /* SERIAL_HAVE_RXDMA */ + +/* Currently RS-485 support cannot be enabled when TXDMA is in use due to + * lack of testing. + */ + +# if (defined(CONFIG_LPUART0_TXDMA) && defined(CONFIG_LPUART0_RS485)) || \ + (defined(CONFIG_LPUART1_TXDMA) && defined(CONFIG_LPUART1_RS485)) || \ + (defined(CONFIG_LPUART2_TXDMA) && defined(CONFIG_LPUART2_RS485)) || \ + (defined(CONFIG_LPUART3_TXDMA) && defined(CONFIG_LPUART3_RS485)) || \ + (defined(CONFIG_LPUART4_TXDMA) && defined(CONFIG_LPUART4_RS485)) || \ + (defined(CONFIG_LPUART5_TXDMA) && defined(CONFIG_LPUART5_RS485)) || \ + (defined(CONFIG_LPUART6_TXDMA) && defined(CONFIG_LPUART6_RS485)) || \ + (defined(CONFIG_LPUART7_TXDMA) && defined(CONFIG_LPUART7_RS485)) + +# error "TXDMA and RS-485 cannot be enabled at the same time for the same LPUART" +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_MCX_NXXX_NXXX_SERIAL_H */ diff --git a/arch/arm/src/mcx-nxxx/nxxx_start.c b/arch/arm/src/mcx-nxxx/nxxx_start.c new file mode 100644 index 0000000000000..93ff2aef59b41 --- /dev/null +++ b/arch/arm/src/mcx-nxxx/nxxx_start.c @@ -0,0 +1,185 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/nxxx_start.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include "nxxx_clockconfig.h" +#include "nxxx_gpio.h" +#include "nxxx_lowputc.h" + +#include "arm_internal.h" +#include "nvic.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define IDLE_STACK ((unsigned)&_ebss + CONFIG_IDLETHREAD_STACKSIZE) + +#ifdef CONFIG_DEBUG_FEATURES +#define showprogress(c) arm_lowputc(c) +#else +# define showprogress(c) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +#ifdef CONFIG_ARMV8M_STACKCHECK +/* we need to get r10 set before we can allow instrumentation calls */ + +void __start(void) noinstrument_function; +#endif + +extern const void * const _vectors[]; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +const uintptr_t g_idle_topstack = IDLE_STACK; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: __start + * + * Description: + * This is the reset entry point. + * + ****************************************************************************/ + +void __start(void) +{ + register const uint32_t *src; + register uint32_t *dest; + + /* Make sure that interrupts are disabled and set MSP */ + + __asm__ __volatile__ ("CPSID i\n"); + __asm__ __volatile__ ("MSR MSP, %0\n" : : "r" (IDLE_STACK) :); + + /* Make sure that we use MSP from now on */ + + __asm__ __volatile__ ("MSR CONTROL, %0\n" : : "r" (0) :); + __asm__ __volatile__ ("ISB SY\n"); + + /* Make sure VECTAB is set to NuttX vector table + * and not the one from the boot ROM and have consistency + * with debugger that automatically set the VECTAB + */ + + putreg32((uint32_t)_vectors, NVIC_VECTAB); + +#ifdef CONFIG_ARMV8M_STACKCHECK + /* Set the stack limit before we attempt to call any functions */ + + __asm__ volatile("sub r10, sp, %0" : : + "r"(CONFIG_IDLETHREAD_STACKSIZE - 64) :); +#endif + + /* Clear .bss. We'll do this inline (vs. calling memset) just to be + * certain that there are no issues with the state of global variables. + */ + + for (dest = (uint32_t *)_sbss; dest < (uint32_t *)_ebss; ) + { + *dest++ = 0; + } + + /* Move the initialized data section from his temporary holding spot in + * FLASH into the correct place in OCRAM. The correct place in OCRAM is + * give by _sdata and _edata. The temporary location is in FLASH at the + * end of all of the other read-only data (.text, .rodata) at _eronly. + */ + + for (src = (const uint32_t *)_eronly, + dest = (uint32_t *)_sdata; dest < (uint32_t *)_edata; + ) + { + *dest++ = *src++; + } + + /* Copy any necessary code sections from FLASH to RAM. The correct + * destination in OCRAM is given by _sramfuncs and _eramfuncs. The + * temporary location is in flash after the data initialization code + * at _framfuncs. This should be done before nxxx_clockconfig() is + * called (in case it has some dependency on initialized C variables). + */ + +#ifdef CONFIG_ARCH_RAMFUNCS + for (src = (const uint32_t *)_framfuncs, + dest = (uint32_t *)_sramfuncs; dest < (uint32_t *)_eramfuncs; + ) + { + *dest++ = *src++; + } +#endif + +#ifdef CONFIG_ARMV8M_STACKCHECK + arm_stack_check_init(); +#endif + + /* Configure the UART so that we can get debug output as soon as possible */ + + nxxx_clockconfig(); + arm_fpuconfig(); + nxxx_lowsetup(); + + /* Initialize onboard resources */ + + nxxx_boardinitialize(); + + /* Enable I- and D-Caches */ + + up_enable_icache(); + up_enable_dcache(); + + /* Perform early serial initialization */ + +#ifdef USE_EARLYSERIALINIT + arm_earlyserialinit(); +#endif + + /* Then start NuttX */ + + nx_start(); + + /* Shouldn't get here */ + + for (; ; ); +} diff --git a/arch/arm/src/mcx-nxxx/nxxx_timerisr.c b/arch/arm/src/mcx-nxxx/nxxx_timerisr.c new file mode 100644 index 0000000000000..6a4f17196204c --- /dev/null +++ b/arch/arm/src/mcx-nxxx/nxxx_timerisr.c @@ -0,0 +1,106 @@ +/**************************************************************************** + * arch/arm/src/mcx-nxxx/nxxx_timerisr.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include "nxxx_clockconfig.h" + +#include "nvic.h" +#include "arm_internal.h" + +#include "clock/clock.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define RELOAD_VALUE (nxxx_get_coreclk() / TICK_PER_SEC) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: nxxx_timerisr + * + * Description: + * The timer ISR will perform a variety of services for various portions + * of the systems. + * + ****************************************************************************/ + +static int nxxx_timerisr(int irq, void *context, void *arg) +{ + /* Process timer interrupt */ + + nxsched_process_timer(); + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: up_timer_initialize + * + * Description: + * This function is called during start-up to initialize + * the timer interrupt. + * + ****************************************************************************/ + +void up_timer_initialize(void) +{ + /* Make sure that the SYSTICK clock source is set to use the SysTick + * function clock (CLKSOURCE==1). + */ + + putreg32(NVIC_SYSTICK_CTRL_CLKSOURCE, NVIC_SYSTICK_CTRL); + + /* Configure SysTick to interrupt at the requested rate */ + + putreg32(RELOAD_VALUE, NVIC_SYSTICK_RELOAD); + putreg32(0, NVIC_SYSTICK_CURRENT); + + /* Attach the timer interrupt vector */ + + irq_attach(NXXX_IRQ_SYSTICK, nxxx_timerisr, NULL); + + /* Enable SysTick interrupts */ + + putreg32((NVIC_SYSTICK_CTRL_CLKSOURCE | NVIC_SYSTICK_CTRL_TICKINT | + NVIC_SYSTICK_CTRL_ENABLE), NVIC_SYSTICK_CTRL); + + /* And enable the timer interrupt */ + + up_enable_irq(NXXX_IRQ_SYSTICK); +} diff --git a/boards/Kconfig b/boards/Kconfig index 0a44beed6961a..a1e4b603ba5e9 100644 --- a/boards/Kconfig +++ b/boards/Kconfig @@ -3234,6 +3234,14 @@ config ARCH_BOARD_AT32F437_MINI ---help--- AT32F437-MINI board based on the Artery AT32F437VMT7 MCU. +config ARCH_BOARD_FRDM_MCXN236 + bool "NXP MCXN236 CPU EVK board" + depends on ARCH_CHIP_N236 + select ARCH_HAVE_IRQBUTTONS + ---help--- + This options selects support for NuttX on the NXP MCXN236 CPU EVK + board with ARM Cortex-M33. + config ARCH_BOARD_CUSTOM bool "Custom development board" ---help--- @@ -3644,6 +3652,7 @@ config ARCH_BOARD default "hpm6750evk2" if ARCH_BOARD_HPM6750EVK2 default "at32f437-mini" if ARCH_BOARD_AT32F437_MINI default "csk6011a-nano" if ARCH_BOARD_CSK6011A_NANO + default "frdm-mcxn236" if ARCH_BOARD_FRDM_MCXN236 comment "Common Board Options" @@ -4678,6 +4687,9 @@ endif if ARCH_BOARD_CSK6011A_NANO source "boards/arm/csk6/csk6011a-nano/Kconfig" endif +if ARCH_BOARD_FRDM_MCXN236 +source "boards/arm/mcx-nxxx/frdm-mcxn236/Kconfig" +endif comment "Board-Common Options" diff --git a/boards/arm/mcx-nxxx/frdm-mcxn236/CMakeLists.txt b/boards/arm/mcx-nxxx/frdm-mcxn236/CMakeLists.txt new file mode 100644 index 0000000000000..4da24ea0831f3 --- /dev/null +++ b/boards/arm/mcx-nxxx/frdm-mcxn236/CMakeLists.txt @@ -0,0 +1,23 @@ +# ############################################################################## +# boards/arm/mcx-nxxx/frdm-mcxn236/CMakeLists.txt +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. The ASF licenses this +# file to you under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# ############################################################################## + +add_subdirectory(src) diff --git a/boards/arm/mcx-nxxx/frdm-mcxn236/Kconfig b/boards/arm/mcx-nxxx/frdm-mcxn236/Kconfig new file mode 100644 index 0000000000000..f72f3c094ce4c --- /dev/null +++ b/boards/arm/mcx-nxxx/frdm-mcxn236/Kconfig @@ -0,0 +1,4 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# diff --git a/boards/arm/mcx-nxxx/frdm-mcxn236/configs/nsh/defconfig b/boards/arm/mcx-nxxx/frdm-mcxn236/configs/nsh/defconfig new file mode 100644 index 0000000000000..ffdf9543bd396 --- /dev/null +++ b/boards/arm/mcx-nxxx/frdm-mcxn236/configs/nsh/defconfig @@ -0,0 +1,48 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="frdm-mcxn236" +CONFIG_ARCH_BOARD_FRDM_MCXN236=y +CONFIG_ARCH_CHIP="mcx-nxxx" +CONFIG_ARCH_CHIP_MCX_NXXX=y +CONFIG_ARCH_CHIP_N236=y +CONFIG_ARCH_INTERRUPTSTACK=4096 +CONFIG_ARCH_STACKDUMP=y +CONFIG_BINFMT_DISABLE=y +CONFIG_BOARD_LOOPSPERMSEC=2664 +CONFIG_BUILTIN=y +CONFIG_SCHED_WAITPID=y +CONFIG_DEBUG_BUSFAULT=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_HARDFAULT_ALERT=y +CONFIG_DEBUG_HARDFAULT_INFO=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEBUG_USAGEFAULT=y +CONFIG_DEFAULT_TASK_STACKSIZE=8192 +CONFIG_FS_PROCFS=y +CONFIG_IDLETHREAD_STACKSIZE=8192 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBC_LOCALTIME=y +CONFIG_LPUART4_SERIAL_CONSOLE=y +CONFIG_NXXX_LPUART4=y +CONFIG_NXXX_GPIO_IRQ=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_DISABLE_IFUPDOWN=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_RAM_SIZE=425984 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_SCHED_BACKTRACE=y +CONFIG_SERIAL_TERMIOS=y +CONFIG_STACK_COLORATION=y +CONFIG_START_DAY=14 +CONFIG_START_MONTH=3 +CONFIG_SYSTEM_NSH=y +CONFIG_TESTING_OSTEST=y diff --git a/boards/arm/mcx-nxxx/frdm-mcxn236/include/board.h b/boards/arm/mcx-nxxx/frdm-mcxn236/include/board.h new file mode 100644 index 0000000000000..2a6177386c55e --- /dev/null +++ b/boards/arm/mcx-nxxx/frdm-mcxn236/include/board.h @@ -0,0 +1,83 @@ +/**************************************************************************** + * boards/arm/mcx-nxxx/frdm-mcxn236/include/board.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM_MCX_NXXX_FRDM_MCXN236_INCLUDE_BOARD_H +#define __BOARDS_ARM_MCX_NXXX_FRDM_MCXN236_INCLUDE_BOARD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PORT_LPUART4_RX PORT_CFG(1, 8, PORT_PCR_MUX_ALT2 | PORT_PCR_IBE) +#define PORT_LPUART4_TX PORT_CFG(1, 9, PORT_PCR_MUX_ALT2 | PORT_PCR_IBE) + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nxxx_boardinitialize + * + * Description: + * All architectures must provide the following entry point. This + * entry point is called in the initialization phase -- after + * imx_memory_initialize and after all memory has been configured and + * mapped but before any devices have been initialized. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void nxxx_boardinitialize(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM_MCX_NXXX_FRDM_MCXN236_INCLUDE_BOARD_H */ diff --git a/boards/arm/mcx-nxxx/frdm-mcxn236/scripts/Make.defs b/boards/arm/mcx-nxxx/frdm-mcxn236/scripts/Make.defs new file mode 100644 index 0000000000000..1eead0df93745 --- /dev/null +++ b/boards/arm/mcx-nxxx/frdm-mcxn236/scripts/Make.defs @@ -0,0 +1,36 @@ +############################################################################ +# boards/arm/mcx-nxxx/frdm-mcxn236/scripts/Make.defs +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(TOPDIR)/.config +include $(TOPDIR)/tools/Config.mk +include $(TOPDIR)/arch/arm/src/armv8-m/Toolchain.defs + +LDSCRIPT = flash.ld + +ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)$(LDSCRIPT) + +CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) +CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS) +CXXFLAGS := $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) +CXXPICFLAGS = $(ARCHPICFLAGS) $(CXXFLAGS) +CPPFLAGS := $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) +AFLAGS := $(CFLAGS) -D__ASSEMBLY__ diff --git a/boards/arm/mcx-nxxx/frdm-mcxn236/scripts/flash.ld b/boards/arm/mcx-nxxx/frdm-mcxn236/scripts/flash.ld new file mode 100644 index 0000000000000..54a66b3254cfd --- /dev/null +++ b/boards/arm/mcx-nxxx/frdm-mcxn236/scripts/flash.ld @@ -0,0 +1,117 @@ +/**************************************************************************** + * boards/arm/mcx-nxxx/frdm-mcxn236/scripts/flash.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * + ****************************************************************************/ + +/* + * Flash controller + * 1) 1 MB of FLASH at 0x0000:0000 + * The on-chip SRAM is split in two parts: + * 1) 96 KB of non-ECC RAM at 0x1400:0000 + * 2) 256 KB of ECC RAM 0x2000:0000 + */ + +MEMORY +{ + flash (rx) : ORIGIN = 0x00000000, LENGTH = 0x01000000 + sram (rw) : ORIGIN = 0x20000000, LENGTH = 256K /* ECC enabled */ + sram2 (rw) : ORIGIN = 0x14000000, LENGTH = 96K /* ECC disabled */ +} + +OUTPUT_ARCH(arm) +EXTERN(_vectors) +ENTRY(__start) + +SECTIONS +{ + .text : + { + _stext = ABSOLUTE(.); + *(.vectors) + *(.text .text.*) + *(.fixup) + *(.gnu.warning) + *(.rodata .rodata.*) + *(.gnu.linkonce.t.*) + *(.glue_7) + *(.glue_7t) + *(.got) + *(.gcc_except_table) + *(.gnu.linkonce.r.*) + _etext = ABSOLUTE(.); + } > flash + + .init_section : + { + _sinit = ABSOLUTE(.); + KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP(*(.init_array .ctors)) + _einit = ABSOLUTE(.); + } > flash + + .ARM.extab : + { + *(.ARM.extab*) + } > flash + + __exidx_start = ABSOLUTE(.); + .ARM.exidx : + { + *(.ARM.exidx*) + } > flash + __exidx_end = ABSOLUTE(.); + + _eronly = ABSOLUTE(.); + + .data : + { + _sdata = ABSOLUTE(.); + *(.data .data.*) + *(.gnu.linkonce.d.*) + CONSTRUCTORS + . = ALIGN(4); + _edata = ABSOLUTE(.); + } > sram AT > flash + + .bss : + { + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _ebss = ABSOLUTE(.); + } > sram + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } +} diff --git a/boards/arm/mcx-nxxx/frdm-mcxn236/scripts/mcx_n236.jlink b/boards/arm/mcx-nxxx/frdm-mcxn236/scripts/mcx_n236.jlink new file mode 100644 index 0000000000000..a7af4b2a0a3f0 --- /dev/null +++ b/boards/arm/mcx-nxxx/frdm-mcxn236/scripts/mcx_n236.jlink @@ -0,0 +1,47 @@ +[BREAKPOINTS] +ForceImpTypeAny = 0 +ShowInfoWin = 1 +EnableFlashBP = 2 +BPDuringExecution = 0 +[CFI] +CFISize = 0x00 +CFIAddr = 0x00 +[CPU] +MonModeVTableAddr = 0xFFFFFFFF +MonModeDebug = 0 +MaxNumAPs = 0 +LowPowerHandlingMode = 0 +OverrideMemMap = 0 +AllowSimulation = 1 +ScriptFile="" +[FLASH] +RMWThreshold = 0x400 +Loaders="" +EraseType = 0x00 +CacheExcludeSize = 0x00 +CacheExcludeAddr = 0x00 +MinNumBytesFlashDL = 0 +SkipProgOnCRCMatch = 1 +VerifyDownload = 1 +AllowCaching = 1 +EnableFlashDL = 2 +Override = 0 +Device="ARM7" +[GENERAL] +MaxNumTransfers = 0x00 +WorkRAMSize = 0x00 +WorkRAMAddr = 0x00 +RAMUsageLimit = 0x00 +[SWO] +SWOLogFile="" +[MEM] +RdOverrideOrMask = 0x00 +RdOverrideAndMask = 0xFFFFFFFF +RdOverrideAddr = 0xFFFFFFFF +WrOverrideOrMask = 0x00 +WrOverrideAndMask = 0xFFFFFFFF +WrOverrideAddr = 0xFFFFFFFF +[RAM] +VerifyDownload = 0x00 +[DYN_MEM_MAP] +NumUserRegion = 0x00 diff --git a/boards/arm/mcx-nxxx/frdm-mcxn236/src/CMakeLists.txt b/boards/arm/mcx-nxxx/frdm-mcxn236/src/CMakeLists.txt new file mode 100644 index 0000000000000..97384ae25b4e5 --- /dev/null +++ b/boards/arm/mcx-nxxx/frdm-mcxn236/src/CMakeLists.txt @@ -0,0 +1,31 @@ +# ############################################################################## +# boards/arm/n23x/frdm-mcxn236/src/CMakeLists.txt +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. The ASF licenses this +# file to you under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# ############################################################################## + +set(SRCS n23x_boardinit.c n23x_bringup.c) + +if(CONFIG_BOARDCTL) + list(APPEND SRCS n23x_appinit.c) +endif() + +target_sources(board PRIVATE ${SRCS}) + +set_property(GLOBAL PROPERTY LD_SCRIPT "${NUTTX_BOARD_DIR}/scripts/flash.ld") diff --git a/boards/arm/mcx-nxxx/frdm-mcxn236/src/Makefile b/boards/arm/mcx-nxxx/frdm-mcxn236/src/Makefile new file mode 100644 index 0000000000000..b99b5913ff9b1 --- /dev/null +++ b/boards/arm/mcx-nxxx/frdm-mcxn236/src/Makefile @@ -0,0 +1,31 @@ +############################################################################ +# boards/arm/mcx-nxxx/frdm-mcxn236/src/Makefile +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(TOPDIR)/Make.defs + +CSRCS = n23x_boardinit.c n23x_bringup.c + +ifeq ($(CONFIG_BOARDCTL),y) +CSRCS += n23x_appinit.c +endif + +include $(TOPDIR)/boards/Board.mk diff --git a/boards/arm/mcx-nxxx/frdm-mcxn236/src/frdm-mcxn236.h b/boards/arm/mcx-nxxx/frdm-mcxn236/src/frdm-mcxn236.h new file mode 100644 index 0000000000000..ee039711d7fc1 --- /dev/null +++ b/boards/arm/mcx-nxxx/frdm-mcxn236/src/frdm-mcxn236.h @@ -0,0 +1,61 @@ +/**************************************************************************** + * boards/arm/mcx-nxxx/frdm-mcxn236/src/frdm-mcxn236.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM_MCX_NXXX_FRDM_MCXN236_SRC_FRDM_MCXN236_H +#define __BOARDS_ARM_MCX_NXXX_FRDM_MCXN236_SRC_FRDM_MCXN236_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Functions Definitions + ****************************************************************************/ + +/**************************************************************************** + * Name: n23x_bringup + * + * Description: + * Bring up board features + * + ****************************************************************************/ + +#if defined(CONFIG_BOARDCTL) || defined(CONFIG_BOARD_LATE_INITIALIZE) +int n23x_bringup(void); +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM_MCX_NXXX_FRDM_MCXN236_SRC_FRDM_MCXN236_H */ diff --git a/boards/arm/mcx-nxxx/frdm-mcxn236/src/n23x_appinit.c b/boards/arm/mcx-nxxx/frdm-mcxn236/src/n23x_appinit.c new file mode 100644 index 0000000000000..c026757f2440a --- /dev/null +++ b/boards/arm/mcx-nxxx/frdm-mcxn236/src/n23x_appinit.c @@ -0,0 +1,76 @@ +/**************************************************************************** + * boards/arm/mcx-nxxx/frdm-mcxn236/src/n23x_appinit.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "frdm-mcxn236.h" + +#ifdef CONFIG_BOARDCTL + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_app_initialize + * + * Description: + * Perform application specific initialization. This function is never + * called directly from application code, but only indirectly via the + * (non-standard) boardctl() interface using the command BOARDIOC_INIT. + * + * Input Parameters: + * arg - The boardctl() argument is passed to the board_app_initialize() + * implementation without modification. The argument has no + * meaning to NuttX; the meaning of the argument is a contract + * between the board-specific initialization logic and the + * matching application logic. The value could be such things as a + * mode enumeration value, a set of DIP switch switch settings, a + * pointer to configuration data read from a file or serial FLASH, + * or whatever you would like to do with it. Every implementation + * should accept zero/NULL as a default configuration. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure to indicate the nature of the failure. + * + ****************************************************************************/ + +int board_app_initialize(uintptr_t arg) +{ + UNUSED(arg); +#ifndef CONFIG_BOARD_LATE_INITIALIZE + /* Perform board initialization */ + + return n23x_bringup(); +#else + return OK; +#endif +} + +#endif /* CONFIG_BOARDCTL */ diff --git a/boards/arm/mcx-nxxx/frdm-mcxn236/src/n23x_boardinit.c b/boards/arm/mcx-nxxx/frdm-mcxn236/src/n23x_boardinit.c new file mode 100644 index 0000000000000..83a1a9a174974 --- /dev/null +++ b/boards/arm/mcx-nxxx/frdm-mcxn236/src/n23x_boardinit.c @@ -0,0 +1,90 @@ +/**************************************************************************** + * boards/arm/mcx-nxxx/frdm-mcxn236/src/n23x_boardinit.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "frdm-mcxn236.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxxx_boardinitialize + * + * Description: + * All architectures must provide the following entry point. This + * entry point is called in the initialization phase -- after + * imx_memory_initialize and after all memory has been configured and + * mapped but before any devices have been initialized. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void nxxx_boardinitialize(void) +{ +#ifdef CONFIG_ARCH_LEDS + /* Configure on-board LEDs if LED support has been selected. */ + +#endif +} + +/**************************************************************************** + * Name: board_late_initialize + * + * Description: + * If CONFIG_BOARD_LATE_INITIALIZE is selected, then an additional + * initialization call will be performed in the boot-up sequence to a + * function called board_late_initialize(). board_late_initialize() will be + * called immediately after up_intitialize() is called and just before the + * initial application is started. This additional initialization phase + * may be used, for example, to initialize board-specific device drivers. + * + ****************************************************************************/ + +#ifdef CONFIG_BOARD_LATE_INITIALIZE +void board_late_initialize(void) +{ + /* Perform board initialization */ + + n23x_bringup(); +} +#endif /* CONFIG_BOARD_LATE_INITIALIZE */ diff --git a/boards/arm/mcx-nxxx/frdm-mcxn236/src/n23x_bringup.c b/boards/arm/mcx-nxxx/frdm-mcxn236/src/n23x_bringup.c new file mode 100644 index 0000000000000..eee06230c4eb9 --- /dev/null +++ b/boards/arm/mcx-nxxx/frdm-mcxn236/src/n23x_bringup.c @@ -0,0 +1,62 @@ +/**************************************************************************** + * boards/arm/mcx-nxxx/frdm-mcxn236/src/n23x_bringup.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include "frdm-mcxn236.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx_bringup + * + * Description: + * Bring up board features + * + ****************************************************************************/ + +int n23x_bringup(void) +{ + int ret; + +#ifdef CONFIG_FS_PROCFS + /* Mount the procfs file system */ + + ret = nx_mount(NULL, "/proc", "procfs", 0, NULL); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to mount procfs at /proc: %d\n", ret); + } +#endif + + UNUSED(ret); + return OK; +} From 0e5cb896c44bc9b602f2e7199a23983f0819f744 Mon Sep 17 00:00:00 2001 From: buxiasen Date: Fri, 21 Feb 2025 19:00:35 +0800 Subject: [PATCH 26/33] binfmt/copyaction: fix prev->flink did not use from kmalloc. We should not modify the input actions, casing when kernel build, userspace call posix_spawn touch kernel address. Signed-off-by: buxiasen --- binfmt/binfmt_copyactions.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/binfmt/binfmt_copyactions.c b/binfmt/binfmt_copyactions.c index b87d4c794655b..715dcbdc753fe 100644 --- a/binfmt/binfmt_copyactions.c +++ b/binfmt/binfmt_copyactions.c @@ -109,7 +109,7 @@ int binfmt_copyactions(FAR const posix_spawn_file_actions_t **copy, } for (entry = (FAR struct spawn_general_file_action_s *)actions, - prev = NULL; entry != NULL; prev = entry, entry = entry->flink) + prev = NULL; entry != NULL; entry = entry->flink) { switch (entry->action) { @@ -122,6 +122,7 @@ int binfmt_copyactions(FAR const posix_spawn_file_actions_t **copy, prev->flink = (FAR void *)close; } + prev = (FAR void *)close; buffer = close + 1; break; @@ -134,6 +135,7 @@ int binfmt_copyactions(FAR const posix_spawn_file_actions_t **copy, prev->flink = (FAR void *)dup2; } + prev = (FAR void *)dup2; buffer = dup2 + 1; break; @@ -149,6 +151,7 @@ int binfmt_copyactions(FAR const posix_spawn_file_actions_t **copy, strcpy(open->path, tmp->path); + prev = (FAR void *)open; buffer = (FAR char *)buffer + ALIGN_UP(SIZEOF_OPEN_FILE_ACTION_S(strlen(tmp->path)), sizeof(FAR void *)); From e0727715162d169ac81817d9d58cccf5f416579d Mon Sep 17 00:00:00 2001 From: buxiasen Date: Sat, 22 Feb 2025 18:28:57 +0800 Subject: [PATCH 27/33] binfmt/copyactions: fix comments, make the actions life cycle more clear Signed-off-by: buxiasen --- binfmt/binfmt.h | 3 ++- binfmt/binfmt_copyactions.c | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/binfmt/binfmt.h b/binfmt/binfmt.h index a60d55318fd43..3cdf07ecbfaed 100644 --- a/binfmt/binfmt.h +++ b/binfmt/binfmt.h @@ -177,7 +177,8 @@ void binfmt_freeargv(FAR char * const *argv); * do not have any real option other than to copy the callers action list. * * Input Parameters: - * copy - Pointer of file actions + * copy - Pointer of the copied output file actions + * actions - Pointer of file actions to be copy * * Returned Value: * A non-zero copy is returned on success. diff --git a/binfmt/binfmt_copyactions.c b/binfmt/binfmt_copyactions.c index 715dcbdc753fe..d1ed70b56d95f 100644 --- a/binfmt/binfmt_copyactions.c +++ b/binfmt/binfmt_copyactions.c @@ -52,7 +52,8 @@ * do not have any real option other than to copy the callers action list. * * Input Parameters: - * copy - Pointer of file actions + * copy - Pointer of the copied output file actions + * actions - Pointer of file actions to be copy * * Returned Value: * A non-zero copy is returned on success. @@ -108,6 +109,11 @@ int binfmt_copyactions(FAR const posix_spawn_file_actions_t **copy, return -ENOMEM; } + /* We need to copy and re-organize the flink chain, be care not modify + * the actions it self, the prev have to point to the last time foreach + * item. + */ + for (entry = (FAR struct spawn_general_file_action_s *)actions, prev = NULL; entry != NULL; entry = entry->flink) { From ee98106bc58a755ff4909831fcedfe5fbbadfdf6 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 18 Feb 2025 11:35:10 +0200 Subject: [PATCH 28/33] arch/risc-v/src/mpfs: Implement wrcomplete support for coremmc driver If CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE is defined, the coremmc driver uses SD card's dat0 line to detect whether the sd card is still busy. This requires that the FPGA design using coremmc block wires dat0 line to some fabric irq; and configures CONFIG_MPFS_COREMMC_WRCOMPLETE_IRQNUM to point to that. Default for the irq number is 4. (MSS_INT_F2M_4) Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/Kconfig | 12 ++++++ arch/risc-v/src/mpfs/mpfs_coremmc.c | 62 +++++++++++++++++++++++++++- arch/risc-v/src/mpfs/mpfs_sdio_dev.h | 3 ++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index 34e459907d074..008e9b4de795f 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -369,6 +369,7 @@ config MPFS_EMMCSD config MPFS_COREMMC bool "COREMMC" select ARCH_HAVE_SDIO + select ARCH_HAVE_SDIOWAIT_WRCOMPLETE select SDIO_BLOCKSETUP default n ---help--- @@ -385,6 +386,17 @@ config MPFS_COREMMC_IRQNUM range 0 63 depends on MPFS_COREMMC +config MPFS_COREMMC_WRCOMPLETE_IRQNUM + int "Number of F2H interrupt" + default 4 + range 0 63 + depends on MPFS_COREMMC + depends on MMCSD_SDIOWAIT_WRCOMPLETE + ---help--- + In case SD card's DAT0 line is connected to an F2H IRQ in the FPGA + design, select CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE and configure the + correct IRQ line here. + config MPFS_IHC_CLIENT bool "IHC slave" depends on RPTUN && !MPFS_BOOTLOADER diff --git a/arch/risc-v/src/mpfs/mpfs_coremmc.c b/arch/risc-v/src/mpfs/mpfs_coremmc.c index 0fe32a282686b..135e6d37eb494 100644 --- a/arch/risc-v/src/mpfs/mpfs_coremmc.c +++ b/arch/risc-v/src/mpfs/mpfs_coremmc.c @@ -210,6 +210,11 @@ static int mpfs_registercallback(struct sdio_dev_s *dev, worker_t callback, void *arg); static void mpfs_callback(void *arg); +#ifdef CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE +static int mpfs_coremmc_wrcomplete_interrupt(int irq, void *context, + void *arg); +#endif + /**************************************************************************** * Private Data ****************************************************************************/ @@ -246,6 +251,10 @@ struct mpfs_dev_s g_coremmc_dev = }, .hw_base = CONFIG_MPFS_COREMMC_BASE, .plic_irq = MPFS_IRQ_FABRIC_F2H_0 + CONFIG_MPFS_COREMMC_IRQNUM, +#ifdef CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE + .wrcomplete_irq = MPFS_IRQ_FABRIC_F2H_0 + + CONFIG_MPFS_COREMMC_WRCOMPLETE_IRQNUM, +#endif .blocksize = 512, .fifo_depth = 0, .onebit = false, @@ -477,6 +486,17 @@ static void mpfs_configwaitints(struct mpfs_dev_s *priv, uint32_t waitmask, flags = enter_critical_section(); +#ifdef CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE + if ((waitevents & SDIOWAIT_WRCOMPLETE) != 0) + { + up_enable_irq(priv->wrcomplete_irq); + } + else if ((priv->waitevents & SDIOWAIT_WRCOMPLETE) != 0) + { + up_disable_irq(priv->wrcomplete_irq); + } +#endif + priv->waitevents = waitevents; priv->wkupevent = wkupevent; priv->waitmask = waitmask; @@ -778,6 +798,34 @@ static void mpfs_endtransfer(struct mpfs_dev_s *priv, } } +/**************************************************************************** + * Name: mpfs_coremmc_wrcomplete_interrupt + * + * Description: + * coremmc interrupt handler for SD card wrcomplete (DAT0) detection + * + * Input Parameters: + * priv - Instance of the coremmc private state structure. + * + * Returned Value: + * OK - Interrupt handled + * + ****************************************************************************/ + +#ifdef CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE +static int mpfs_coremmc_wrcomplete_interrupt(int irq, void *context, + void *arg) +{ + struct mpfs_dev_s *priv = (struct mpfs_dev_s *)arg; + + DEBUGASSERT(priv != NULL); + + mpfs_endwait(priv, SDIOWAIT_WRCOMPLETE); + + return OK; +} +#endif + /**************************************************************************** * Name: mpfs_coremmc_interrupt * @@ -1311,7 +1359,19 @@ static int mpfs_attach(struct sdio_dev_s *dev) mpfs_putreg8(priv, 0x00, MPFS_COREMMC_MBIMR); mpfs_putreg8(priv, 0xff, MPFS_COREMMC_MBICR); - up_enable_irq(priv->plic_irq); +#ifdef CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE + ret = irq_attach(priv->wrcomplete_irq, + mpfs_coremmc_wrcomplete_interrupt, priv); + + if (ret != OK) + { + irq_detach(priv->plic_irq); + } + else +#endif + { + up_enable_irq(priv->plic_irq); + } } mcinfo("attach: %d\n", ret); diff --git a/arch/risc-v/src/mpfs/mpfs_sdio_dev.h b/arch/risc-v/src/mpfs/mpfs_sdio_dev.h index 7b0774bde782d..10e36c608436b 100644 --- a/arch/risc-v/src/mpfs/mpfs_sdio_dev.h +++ b/arch/risc-v/src/mpfs/mpfs_sdio_dev.h @@ -44,6 +44,9 @@ struct mpfs_dev_s const uintptr_t hw_base; /* Base address */ const int plic_irq; /* PLIC interrupt */ +#ifdef CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE + const int wrcomplete_irq; /* Card write complete interrupt */ +#endif bool clk_enabled; /* Clk state */ /* eMMC / SD and HW parameters */ From 824dd706177444d020ebb20acdc08c294ab0db37 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 19 Feb 2025 10:13:15 +0200 Subject: [PATCH 29/33] arch/risc-v/src/mpfs: Move PLIC interrupt enable/disable to mpfs_plic.c and handle pending interrupts - Move PLIC interrupt enable and disable functions into mpfs_plic.c - When enabling interrupts, always clear pending interrupt - Remove race conditions between irq enable/disable by adding spinlock - An interrupt may trigger on one hart in the middle of enabling the interrupts - then the interrupt handler might call up_disable_irq. A pending interrupt would trigger immediately when enabling the interrupt source, but this is not expected. The interrupt source is level sensitive, so it should only trigger if the source is active at the time when it is enabled. Not if it was active sometime in the past. Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/hardware/mpfs_plic.h | 4 + arch/risc-v/src/mpfs/mpfs_irq.c | 41 +------- arch/risc-v/src/mpfs/mpfs_plic.c | 122 ++++++++++++++++++++++ arch/risc-v/src/mpfs/mpfs_plic.h | 26 +++++ 4 files changed, 155 insertions(+), 38 deletions(-) diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_plic.h b/arch/risc-v/src/mpfs/hardware/mpfs_plic.h index e50e987f934c8..04fcb4b35c1bc 100644 --- a/arch/risc-v/src/mpfs/hardware/mpfs_plic.h +++ b/arch/risc-v/src/mpfs/hardware/mpfs_plic.h @@ -38,6 +38,10 @@ #define MPFS_PLIC_IP4 (MPFS_PLIC_BASE + 0x001010) #define MPFS_PLIC_I51 (MPFS_PLIC_BASE + 0x001014) +#define MPFS_PLIC_PRIO_DIS 0 +#define MPFS_PLIC_PRIO_MIN 1 +#define MPFS_PLIC_PRIO_MAX 7 + #define MPFS_HART_MIE_OFFSET (0x100) #define MPFS_HART_SIE_OFFSET (0x80) diff --git a/arch/risc-v/src/mpfs/mpfs_irq.c b/arch/risc-v/src/mpfs/mpfs_irq.c index b9a7e4a4ebe9b..01111cef9a418 100644 --- a/arch/risc-v/src/mpfs/mpfs_irq.c +++ b/arch/risc-v/src/mpfs/mpfs_irq.c @@ -69,7 +69,7 @@ void up_irqinitialize(void) for (int id = 1; id <= NR_IRQS; id++) { - putreg32(1, MPFS_PLIC_PRIORITY + (4 * id)); + putreg32(MPFS_PLIC_PRIO_MIN, MPFS_PLIC_PRIORITY + (4 * id)); } /* Attach the common interrupt handler */ @@ -103,7 +103,6 @@ void up_irqinitialize(void) void up_disable_irq(int irq) { int extirq = 0; - int i; if (irq == RISCV_IRQ_SOFT) { @@ -125,31 +124,7 @@ void up_disable_irq(int irq) PANIC(); } - /* Disable the irq on all harts */ - - for (i = 0; i < CONFIG_SMP_NCPUS; i++) - { - uintptr_t iebase = mpfs_plic_get_iebase(riscv_cpuid_to_hartid(i)); - uintptr_t claim_address = - mpfs_plic_get_claimbase(riscv_cpuid_to_hartid(i)); - - /* Clear any already claimed IRQ (this must be done BEFORE - * disabling the interrupt source): - * - * To signal the completion of executing an interrupt handler, the - * processor core writes the received interrupt ID to the - * Claim/Complete register. The PLIC does not check whether the - * completion ID is the same as the last claim ID for that target. - * If the completion ID does not match an interrupt source that is - * currently enabled for the target, the completion is ignored. - */ - - putreg32(extirq, claim_address); - - /* Clear enable bit for the irq */ - - modifyreg32(iebase + (4 * (extirq / 32)), 1 << (extirq % 32), 0); - } + mpfs_plic_disable_irq(extirq); } } @@ -164,7 +139,6 @@ void up_disable_irq(int irq) void up_enable_irq(int irq) { int extirq; - int i; if (irq == RISCV_IRQ_SOFT) { @@ -186,16 +160,7 @@ void up_enable_irq(int irq) PANIC(); } - /* Enable the irq on all harts */ - - for (i = 0; i < CONFIG_SMP_NCPUS; i++) - { - uintptr_t iebase = mpfs_plic_get_iebase(riscv_cpuid_to_hartid(i)); - - /* Set enable bit for the irq */ - - modifyreg32(iebase + (4 * (extirq / 32)), 0, 1 << (extirq % 32)); - } + mpfs_plic_clear_and_enable_irq(extirq); } } diff --git a/arch/risc-v/src/mpfs/mpfs_plic.c b/arch/risc-v/src/mpfs/mpfs_plic.c index 5dc9733a25d28..2e984596df89e 100644 --- a/arch/risc-v/src/mpfs/mpfs_plic.c +++ b/arch/risc-v/src/mpfs/mpfs_plic.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,12 @@ # define MPFS_PLIC_THRESHOLDPRIV_OFFSET (0) #endif +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static volatile spinlock_t g_enable_lock = SP_UNLOCKED; + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -215,3 +222,118 @@ uintptr_t mpfs_plic_get_thresholdbase(void) { return get_thresholdbase(up_cpu_index()); } + +/**************************************************************************** + * Name: mpfs_plic_disable_irq(int extirq) + * + * Description: + * Disable interrupt on all harts + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mpfs_plic_disable_irq(int extirq) +{ + uintptr_t iebase; + uintptr_t claim_address; + int i; + + irqstate_t flags = spin_lock_irqsave(&g_enable_lock); + + /* Disable the irq on all harts */ + + for (i = 0; i < CONFIG_SMP_NCPUS; i++) + { + /* Clear any already claimed IRQ (this must be done BEFORE + * disabling the interrupt source): + * + * To signal the completion of executing an interrupt handler, the + * processor core writes the received interrupt ID to the + * Claim/Complete register. The PLIC does not check whether the + * completion ID is the same as the last claim ID for that target. + * If the completion ID does not match an interrupt source that is + * currently enabled for the target, the completion is ignored. + */ + + claim_address = mpfs_plic_get_claimbase(riscv_cpuid_to_hartid(i)); + putreg32(extirq, claim_address); + + /* Clear enable bit for the irq for every hart */ + + iebase = mpfs_plic_get_iebase(riscv_cpuid_to_hartid(i)); + modifyreg32(iebase + (4 * (extirq / 32)), 1 << (extirq % 32), 0); + } + + spin_unlock_irqrestore(&g_enable_lock, flags); +} + +/**************************************************************************** + * Name: mpfs_plic_clear_and_enable_irq + * + * Description: + * Enable interrupt; if it is pending, clear it first + * + * Assumptions: + * - Irq can only be pending, all the irq sources are disabled + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mpfs_plic_clear_and_enable_irq(int extirq) +{ + int hartid = up_cpu_index(); + uintptr_t claim_address = mpfs_plic_get_claimbase(hartid); + uintptr_t iebase = mpfs_plic_get_iebase(hartid); + uintptr_t pending_address = MPFS_PLIC_IP0 + (4 * (extirq / 32)); + int i; + uint32_t claim; + + irqstate_t flags = spin_lock_irqsave(&g_enable_lock); + + /* Check if the extirq is pending */ + + if ((getreg32(pending_address) & (1 << (extirq % 32))) != 0) + { + /* Interrupt is pending. This means that the source is disabled on + * all harts. Only way to clear it is to claim and ack it; do it on + * this hart + * + * First bump the priority of the irq to highest, to get it to the + * head of the claim queue + */ + + putreg32(MPFS_PLIC_PRIO_MAX, MPFS_PLIC_PRIORITY + (4 * extirq)); + + /* Enable the irq on this hart */ + + modifyreg32(iebase + (4 * (extirq / 32)), 0, 1 << (extirq % 32)); + + /* Now we can claim and ack the pending irq */ + + claim = getreg32(claim_address); + + DEBUGASSERT(claim == extirq); + + putreg32(claim, claim_address); + + /* Return the irq priority to mininum */ + + putreg32(MPFS_PLIC_PRIO_MIN, MPFS_PLIC_PRIORITY + (4 * extirq)); + } + + /* Enable the irq on all harts */ + + for (i = 0; i < CONFIG_SMP_NCPUS; i++) + { + /* Set enable bit for the irq */ + + iebase = mpfs_plic_get_iebase(riscv_cpuid_to_hartid(i)); + modifyreg32(iebase + (4 * (extirq / 32)), 0, 1 << (extirq % 32)); + } + + spin_unlock_irqrestore(&g_enable_lock, flags); +} diff --git a/arch/risc-v/src/mpfs/mpfs_plic.h b/arch/risc-v/src/mpfs/mpfs_plic.h index 00aa6ef368e65..d6563da37c3eb 100644 --- a/arch/risc-v/src/mpfs/mpfs_plic.h +++ b/arch/risc-v/src/mpfs/mpfs_plic.h @@ -88,4 +88,30 @@ uintptr_t mpfs_plic_get_claimbase(uintptr_t hartid); uintptr_t mpfs_plic_get_thresholdbase(void); +/**************************************************************************** + * Name: mpfs_plic_disable_irq(int extirq) + * + * Description: + * Disable interrupt on all harts + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mpfs_plic_disable_irq(int extirq); + +/**************************************************************************** + * Name: mpfs_plic_clear_and_enable_irq + * + * Description: + * Enable interrupt; if it is pending, clear it first + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mpfs_plic_clear_and_enable_irq(int extirq); + #endif /* __ARCH_RISC_V_SRC_MPFS_MPFS_PLIC_H */ From 7ccd6e9041aae0e24c163f62447f5d9e3b270c6c Mon Sep 17 00:00:00 2001 From: Michal Lenc Date: Wed, 12 Feb 2025 15:23:09 +0100 Subject: [PATCH 30/33] samv7/pwm: add support for latched fault inputs This adds configuration option for every fault input, that can be latched (kept even after the input value is below the threshold) or volatile (PWM is automatically enabled once the output polarity goes back to the normal state). Signed-off-by: Michal Lenc --- arch/arm/src/samv7/Kconfig | 185 ++++++++++++++++++++++++++++++++++- arch/arm/src/samv7/sam_pwm.c | 6 +- arch/arm/src/samv7/sam_pwm.h | 104 ++++++++++++++++++++ 3 files changed, 293 insertions(+), 2 deletions(-) diff --git a/arch/arm/src/samv7/Kconfig b/arch/arm/src/samv7/Kconfig index 195812ad4f15f..c3ecbbe3b58a2 100644 --- a/arch/arm/src/samv7/Kconfig +++ b/arch/arm/src/samv7/Kconfig @@ -857,6 +857,15 @@ config SAMV7_PWM0_PA9_POL Fault input is by default active on high level. This config inverts the logic and makes fault active on low level. +config SAMV7_PWM0_PA9_LATCHED + bool "Latched fault" + default n + ---help--- + When this option is selected, the fault input remains active until it + is cleared by the software. When this option is not selected, the + fault is cleared once the fault input changes its polarity level back + to normal state. + endif config SAMV7_PWM0_PD8 @@ -872,6 +881,15 @@ config SAMV7_PWM0_PD8_POL Fault input is by default active on high level. This config inverts the logic and makes fault active on low level. +config SAMV7_PWM0_PD8_LATCHED + bool "Latched fault" + default n + ---help--- + When this option is selected, the fault input remains active until it + is cleared by the software. When this option is not selected, the + fault is cleared once the fault input changes its polarity level back + to normal state. + endif config SAMV7_PWM0_PD9 @@ -887,28 +905,102 @@ config SAMV7_PWM0_PD9_POL Fault input is by default active on high level. This config inverts the logic and makes fault active on low level. +config SAMV7_PWM0_PD9_LATCHED + bool "Latched fault" + default n + ---help--- + When this option is selected, the fault input remains active until it + is cleared by the software. When this option is not selected, the + fault is cleared once the fault input changes its polarity level back + to normal state. + endif config SAMV7_PWM0_PMC bool "External fault input from PMC" default n +if SAMV7_PWM0_PMC + +config SAMV7_PWM0_PMC_LATCHED + bool "Latched fault" + default n + ---help--- + When this option is selected, the fault input remains active until it + is cleared by the software. When this option is not selected, the + fault is cleared once the fault input changes its polarity level back + to normal state. + +endif + config SAMV7_PWM0_AFEC0 bool "External fault input from AFEC0" default n +if SAMV7_PWM0_AFEC0 + +config SAMV7_PWM0_AFEC0_LATCHED + bool "Latched fault" + default n + ---help--- + When this option is selected, the fault input remains active until it + is cleared by the software. When this option is not selected, the + fault is cleared once the fault input changes its polarity level back + to normal state. + +endif + config SAMV7_PWM0_AFEC1 bool "External fault input from AFEC1" default n +if SAMV7_PWM0_AFEC1 + +config SAMV7_PWM0_AFEC1_LATCHED + bool "Latched fault" + default n + ---help--- + When this option is selected, the fault input remains active until it + is cleared by the software. When this option is not selected, the + fault is cleared once the fault input changes its polarity level back + to normal state. + +endif + config SAMV7_PWM0_ACC bool "External fault input from ACC" default n +if SAMV7_PWM0_ACC + +config SAMV7_PWM0_ACC_LATCHED + bool "Latched fault" + default n + ---help--- + When this option is selected, the fault input remains active until it + is cleared by the software. When this option is not selected, the + fault is cleared once the fault input changes its polarity level back + to normal state. + +endif + config SAMV7_PWM0_TIM0 bool "External fault input from Timer 0" default n +if SAMV7_PWM0_TIM0 + +config SAMV7_PWM0_TIM0_LATCHED + bool "Latched fault" + default n + ---help--- + When this option is selected, the fault input remains active until it + is cleared by the software. When this option is not selected, the + fault is cleared once the fault input changes its polarity level back + to normal state. + +endif + endmenu config SAMV7_PWM0_EVENT0 @@ -1118,6 +1210,15 @@ config SAMV7_PWM1_PA21_POL Fault input is by default active on high level. This config inverts the logic and makes fault active on low level. +config SAMV7_PWM1_PA21_LATCHED + bool "Latched fault" + default n + ---help--- + When this option is selected, the fault input remains active until it + is cleared by the software. When this option is not selected, the + fault is cleared once the fault input changes its polarity level back + to normal state. + endif config SAMV7_PWM1_PA26 @@ -1133,6 +1234,15 @@ config SAMV7_PWM1_PA26_POL Fault input is by default active on high level. This config inverts the logic and makes fault active on low level. +config SAMV7_PWM1_PA26_LATCHED + bool "Latched fault" + default n + ---help--- + When this option is selected, the fault input remains active until it + is cleared by the software. When this option is not selected, the + fault is cleared once the fault input changes its polarity level back + to normal state. + endif config SAMV7_PWM1_PA28 @@ -1148,30 +1258,103 @@ config SAMV7_PWM1_PA28_POL Fault input is by default active on high level. This config inverts the logic and makes fault active on low level. +config SAMV7_PWM1_PA28_LATCHED + bool "Latched fault" + default n + ---help--- + When this option is selected, the fault input remains active until it + is cleared by the software. When this option is not selected, the + fault is cleared once the fault input changes its polarity level back + to normal state. + endif config SAMV7_PWM1_PMC bool "External fault input from PMC" default n +if SAMV7_PWM1_PMC + +config SAMV7_PWM1_PMC_LATCHED + bool "Latched fault" + default n + ---help--- + When this option is selected, the fault input remains active until it + is cleared by the software. When this option is not selected, the + fault is cleared once the fault input changes its polarity level back + to normal state. + +endif + config SAMV7_PWM1_AFEC0 bool "External fault input from AFEC0" default n +if SAMV7_PWM1_AFEC0 + +config SAMV7_PWM1_AFEC0_LATCHED + bool "Latched fault" + default n + ---help--- + When this option is selected, the fault input remains active until it + is cleared by the software. When this option is not selected, the + fault is cleared once the fault input changes its polarity level back + to normal state. + +endif + config SAMV7_PWM1_AFEC1 bool "External fault input from AFEC1" default n +if SAMV7_PWM1_AFEC1 + +config SAMV7_PWM1_AFEC1_LATCHED + bool "Latched fault" + default n + ---help--- + When this option is selected, the fault input remains active until it + is cleared by the software. When this option is not selected, the + fault is cleared once the fault input changes its polarity level back + to normal state. + +endif + config SAMV7_PWM1_ACC bool "External fault input from ACC" default n +if SAMV7_PWM1_ACC + +config SAMV7_PWM1_ACC_LATCHED + bool "Latched fault" + default n + ---help--- + When this option is selected, the fault input remains active until it + is cleared by the software. When this option is not selected, the + fault is cleared once the fault input changes its polarity level back + to normal state. + +endif + config SAMV7_PWM1_TIM0 bool "External fault input from Timer 0" default n -endmenu +if SAMV7_PWM1_TIM0 +config SAMV7_PWM1_TIM0_LATCHED + bool "Latched fault" + default n + ---help--- + When this option is selected, the fault input remains active until it + is cleared by the software. When this option is not selected, the + fault is cleared once the fault input changes its polarity level back + to normal state. + +endif + +endmenu config SAMV7_PWM1_EVENT0 bool "Generate trigger on Event Line 0" diff --git a/arch/arm/src/samv7/sam_pwm.c b/arch/arm/src/samv7/sam_pwm.c index 94ab493e6ea61..a7f196dbc7fba 100644 --- a/arch/arm/src/samv7/sam_pwm.c +++ b/arch/arm/src/samv7/sam_pwm.c @@ -100,6 +100,7 @@ struct sam_pwm_fault_s { uint8_t source; /* Source of fault input */ uint8_t polarity; + uint8_t latched; /* Latched fault inputs */ gpio_pinset_t gpio_0; /* GPIO 1 fault input */ gpio_pinset_t gpio_1; /* GPIO 2 fault input */ gpio_pinset_t gpio_2; /* GPIO 3 fault input */ @@ -234,6 +235,7 @@ static struct sam_pwm_fault_s g_pwm0_fault = { .source = PWM0_FAULTS, .polarity = PWM0_POL, + .latched = PWM0_LATCH, .gpio_0 = GPIO_PWMC0_FI0, .gpio_1 = GPIO_PWMC0_FI1, .gpio_2 = GPIO_PWMC0_FI2, @@ -378,6 +380,7 @@ static struct sam_pwm_fault_s g_pwm1_fault = { .source = PWM1_FAULTS, .polarity = PWM1_POL, + .latched = PWM1_LATCH, .gpio_0 = GPIO_PWMC1_FI0, .gpio_1 = GPIO_PWMC1_FI1, .gpio_2 = GPIO_PWMC1_FI2, @@ -889,7 +892,8 @@ static int pwm_setup(struct pwm_lowerhalf_s *dev) * is set via configuration options. */ - regval = FMR_FPOL_SEL(priv->fault->polarity); + regval = FMR_FPOL_SEL(priv->fault->polarity) | + FMR_FMOD_SEL(priv->fault->latched); pwm_putreg(priv, SAMV7_PWM_FMR, regval); /* Force both outputs to 0 if fault occurs */ diff --git a/arch/arm/src/samv7/sam_pwm.h b/arch/arm/src/samv7/sam_pwm.h index f4b154f249af1..6cd8168f26e35 100644 --- a/arch/arm/src/samv7/sam_pwm.h +++ b/arch/arm/src/samv7/sam_pwm.h @@ -99,9 +99,15 @@ #else #define PWM0_PA9_POL 1 #endif +#ifdef CONFIG_SAMV7_PWM0_PA9_LATCHED +#define PWM0_PA9_LATCH 1 +#else +#define PWM0_PA9_LATCH 0 +#endif #else #define PWM0_PA9 0 #define PWM0_PA9_POL 0 +#define PWM0_PA9_LATCH 0 #endif #ifdef CONFIG_SAMV7_PWM0_PD8 @@ -111,9 +117,15 @@ #else #define PWM0_PD8_POL (1 << 1) #endif +#ifdef CONFIG_SAMV7_PWM0_PD8_LATCHED +#define PWM0_PD8_LATCH (1 << 1) +#else +#define PWM0_PD8_LATCH 0 +#endif #else #define PWM0_PD8 0 #define PWM0_PD8_POL 0 +#define PWM0_PD8_LATCH 0 #endif #ifdef CONFIG_SAMV7_PWM0_PD9 @@ -123,39 +135,75 @@ #else #define PWM0_PD9_POL (1 << 2) #endif +#ifdef CONFIG_SAMV7_PWM0_PD9_LATCHED +#define PWM0_PD9_LATCH (1 << 2) +#else +#define PWM0_PD9_LATCH 0 +#endif #else #define PWM0_PD9 0 #define PWM0_PD9_POL 0 +#define PWM0_PD9_LATCH 0 #endif #ifdef CONFIG_SAMV7_PWM0_PMC #define PWM0_PMC (1 << 3) +#ifdef CONFIG_SAMV7_PWM0_PMC_LATCHED +#define PWM0_PMC_LATCH (1 << 3) +#else +#define PWM0_PMC_LATCH 0 +#endif #else #define PWM0_PMC 0 +#define PWM0_PMC_LATCH 0 #endif #ifdef CONFIG_SAMV7_PWM0_AFEC0 #define PWM0_AFEC0 (1 << 4) +#ifdef CONFIG_SAMV7_PWM0_AFEC0_LATCHED +#define PWM0_AFEC0_LATCH (1 << 4) +#else +#define PWM0_AFEC0_LATCH 0 +#endif #else #define PWM0_AFEC0 0 +#define PWM0_AFEC0_LATCH 0 #endif #ifdef CONFIG_SAMV7_PWM0_AFEC1 #define PWM0_AFEC1 (1 << 5) +#ifdef CONFIG_SAMV7_PWM0_AFEC1_LATCHED +#define PWM0_AFEC1_LATCH (1 << 5) +#else +#define PWM0_AFEC1_LATCH 0 +#endif #else #define PWM0_AFEC1 0 +#define PWM0_AFEC1_LATCH 0 #endif #ifdef CONFIG_SAMV7_PWM0_ACC #define PWM0_ACC (1 << 6) +#ifdef CONFIG_SAMV7_PWM0_ACC_LATCHED +#define PWM0_ACC_LATCH (1 << 6) +#else +#define PWM0_ACC_LATCH 0 +#endif #else #define PWM0_ACC 0 +#define PWM0_ACC_LATCH 0 #endif #ifdef CONFIG_SAMV7_PWM0_TIM0 #define PWM0_TIM0 (1 << 7) +#ifdef CONFIG_SAMV7_PWM0_TIM0_LATCHED +#define PWM0_TIM0_LATCH (1 << 7) +#else +#define PWM0_TIM0_LATCH 0 +#endif #else #define PWM0_TIM0 0 +#define PWM0_TIM0_LATCH 0 #endif #define PWM0_FAULTS (PWM0_PA9 + PWM0_PD8 + PWM0_PD9 + PWM0_PMC + \ @@ -165,6 +213,10 @@ PWM0_PMC + PWM0_AFEC0 + PWM0_AFEC1 + PWM0_ACC + \ PWM0_TIM0) +#define PWM0_LATCH (PWM0_PA9_LATCH + PWM0_PD8_LATCH + PWM0_PD9_LATCH + \ + PWM0_PMC_LATCH + PWM0_AFEC0_LATCH + PWM0_AFEC1_LATCH + \ + PWM0_ACC_LATCH + PWM0_TIM0_LATCH) + #ifdef CONFIG_SAMV7_PWM1_PA21 #define PWM1_PA21 1 #ifdef CONFIG_SAMV7_PWM1_PA21_POL @@ -172,9 +224,15 @@ #else #define PWM1_PA21_POL 1 #endif +#ifdef CONFIG_SAMV7_PWM1_PA21_LATCHED +#define PWM1_PA21_LATCH 1 +#else +#define PWM1_PA21_LATCH 0 +#endif #else #define PWM1_PA21 0 #define PWM1_PA21_POL 0 +#define PWM1_PA21_LATCH 0 #endif #ifdef CONFIG_SAMV7_PWM1_PA26 @@ -184,9 +242,15 @@ #else #define PWM1_PA26_POL (1 << 1) #endif +#ifdef CONFIG_SAMV7_PWM1_PA26_LATCHED +#define PWM1_PA26_LATCH (1 << 1) +#else +#define PWM1_PA26_LATCH 0 +#endif #else #define PWM1_PA26 0 #define PWM1_PA26_POL 0 +#define PWM1_PA26_LATCH 0 #endif #ifdef CONFIG_SAMV7_PWM1_PA28 @@ -196,39 +260,75 @@ #else #define PWM1_PA28_POL (1 << 2) #endif +#ifdef CONFIG_SAMV7_PWM1_PA28_LATCHED +#define PWM1_PA28_LATCH (1 << 2) +#else +#define PWM1_PA28_LATCH 0 +#endif #else #define PWM1_PA28 0 #define PWM1_PA28_POL 0 +#define PWM1_PA28_LATCH 0 #endif #ifdef CONFIG_SAMV7_PWM1_PMC #define PWM1_PMC (1 << 3) +#ifdef CONFIG_SAMV7_PWM1_PMC_LATCHED +#define PWM1_PMC_LATCH (1 << 3) +#else +#define PWM1_PMC_LATCH 0 +#endif #else #define PWM1_PMC 0 +#define PWM1_PMC_LATCH 0 #endif #ifdef CONFIG_SAMV7_PWM1_AFEC0 #define PWM1_AFEC0 (1 << 4) +#ifdef CONFIG_SAMV7_PWM1_AFEC0_LATCHED +#define PWM1_AFEC0_LATCH (1 << 4) +#else +#define PWM1_AFEC0_LATCH 0 +#endif #else #define PWM1_AFEC0 0 +#define PWM1_AFEC0_LATCH 0 #endif #ifdef CONFIG_SAMV7_PWM1_AFEC1 #define PWM1_AFEC1 (1 << 5) +#ifdef CONFIG_SAMV7_PWM1_AFEC1_LATCHED +#define PWM1_AFEC1_LATCH (1 << 5) +#else +#define PWM1_AFEC1_LATCH 0 +#endif #else #define PWM1_AFEC1 0 +#define PWM1_AFEC1_LATCH 0 #endif #ifdef CONFIG_SAMV7_PWM1_ACC #define PWM1_ACC (1 << 6) +#ifdef CONFIG_SAMV7_PWM1_ACC_LATCHED +#define PWM1_ACC_LATCH (1 << 6) +#else +#define PWM1_ACC_LATCH 0 +#endif #else +#define PWM1_ACC_LATCH 0 #define PWM1_ACC 0 #endif #ifdef CONFIG_SAMV7_PWM1_TIM0 #define PWM1_TIM0 (1 << 7) +#ifdef CONFIG_SAMV7_PWM1_TIM0_LATCHED +#define PWM1_TIM0_LATCH (1 << 7) +#else +#define PWM1_TIM0_LATCH 0 +#endif #else #define PWM1_TIM0 0 +#define PWM1_TIM0_LATCH 0 #endif #define PWM1_FAULTS (PWM1_PA21 + PWM1_PA26 + PWM1_PA28 + PWM1_PMC + \ @@ -238,6 +338,10 @@ PWM1_PMC + PWM1_AFEC0 + PWM1_AFEC1 + PWM1_ACC + \ PWM1_TIM0) +#define PWM1_LATCH (PWM1_PA21_LATCH + PWM1_PA26_LATCH + PWM1_PA28_LATCH + \ + PWM1_PMC_LATCH + PWM1_AFEC0_LATCH + PWM1_AFEC1_LATCH + \ + PWM1_ACC_LATCH + PWM1_TIM0_LATCH) + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ From 8956fc440fd4c379020c7d36b8fa46fdbf529eb2 Mon Sep 17 00:00:00 2001 From: Tiago Medicci Serrano Date: Fri, 31 Jan 2025 11:26:17 -0300 Subject: [PATCH 31/33] xtensa/esp32[|s3]: re-enable cache during exception handler This commit implements re-enabling the cache before the exception handler for ESP32-S3 and removes unnecessary checks (cache should always be re-enabled during an exception handler and disabled again after processed, except for ESP32-S3 that implements no recoverable exceptions). Signed-off-by: Tiago Medicci Serrano --- arch/xtensa/src/esp32/Kconfig | 9 ----- arch/xtensa/src/esp32/esp32_user.c | 41 ++++++++++++++----- arch/xtensa/src/esp32s3/esp32s3_spiflash.c | 46 ++++++++++++---------- arch/xtensa/src/esp32s3/esp32s3_spiflash.h | 16 ++++++++ arch/xtensa/src/esp32s3/esp32s3_user.c | 11 ++++++ 5 files changed, 84 insertions(+), 39 deletions(-) diff --git a/arch/xtensa/src/esp32/Kconfig b/arch/xtensa/src/esp32/Kconfig index 082cddbd93b66..4e343c5cf8e88 100644 --- a/arch/xtensa/src/esp32/Kconfig +++ b/arch/xtensa/src/esp32/Kconfig @@ -207,15 +207,6 @@ config ESP32_RUN_IRAM This loads all of NuttX inside IRAM. Used to test somewhat small images that can fit entirely in IRAM. -config ESP32_EXCEPTION_ENABLE_CACHE - bool - default y - depends on ESP32_SPIFLASH - ---help--- - When an exception triggers, the panic function reenables the SPI Flash - cache to allow functions that are located in SPI Flash to run. - Disable this option to save IRAM space. - menu "ESP32 Peripheral Selection" source "arch/xtensa/src/common/espressif/Kconfig" diff --git a/arch/xtensa/src/esp32/esp32_user.c b/arch/xtensa/src/esp32/esp32_user.c index 051dcfdbcf058..4f70f7a4f8020 100644 --- a/arch/xtensa/src/esp32/esp32_user.c +++ b/arch/xtensa/src/esp32/esp32_user.c @@ -324,16 +324,19 @@ static void advance_pc(uint32_t *regs, int diff) uint32_t *xtensa_user(int exccause, uint32_t *regs) { -#ifdef CONFIG_ESP32_EXCEPTION_ENABLE_CACHE +#ifdef CONFIG_ESP32_SPIFLASH + bool is_cache_reenabled = false; + if (!spi_flash_cache_enabled()) { + is_cache_reenabled = true; + spi_enable_cache(0); -#ifdef CONFIG_SMP +# ifdef CONFIG_SMP spi_enable_cache(1); -#endif - _err("\nERROR: Cache was disabled and re-enabled\n"); +# endif } -#endif +#endif /* CONFIG_ESP32_SPIFLASH */ #ifdef CONFIG_ARCH_USE_TEXT_HEAP /* Emulate byte access for module text. @@ -375,7 +378,7 @@ uint32_t *xtensa_user(int exccause, uint32_t *regs) store_uint8(((uint8_t *)regs[REG_A0 + s]) + imm8, regs[REG_A0 + t]); advance_pc(regs, 3); - return regs; + goto return_with_regs; } else if (decode_s16i(pc, &imm8, &s, &t)) { @@ -391,7 +394,7 @@ uint32_t *xtensa_user(int exccause, uint32_t *regs) store_uint8((uint8_t *)va, regs[REG_A0 + t]); store_uint8((uint8_t *)va + 1, regs[REG_A0 + t] >> 8); advance_pc(regs, 3); - return regs; + goto return_with_regs; } else if (decode_l8ui(pc, &imm8, &s, &t)) { @@ -406,7 +409,7 @@ uint32_t *xtensa_user(int exccause, uint32_t *regs) regs[REG_A0 + t] = load_uint8(((uint8_t *)regs[REG_A0 + s]) + imm8); advance_pc(regs, 3); - return regs; + goto return_with_regs; } else if (decode_l16si(pc, &imm8, &s, &t)) { @@ -423,7 +426,7 @@ uint32_t *xtensa_user(int exccause, uint32_t *regs) uint8_t hi = load_uint8((uint8_t *)va + 1); regs[REG_A0 + t] = (int16_t)((hi << 8) | lo); advance_pc(regs, 3); - return regs; + goto return_with_regs; } else if (decode_l16ui(pc, &imm8, &s, &t)) { @@ -440,11 +443,29 @@ uint32_t *xtensa_user(int exccause, uint32_t *regs) uint8_t hi = load_uint8((uint8_t *)va + 1); regs[REG_A0 + t] = (hi << 8) | lo; advance_pc(regs, 3); - return regs; + goto return_with_regs; } + +return_with_regs: +# ifdef CONFIG_ESP32_SPIFLASH + if (is_cache_reenabled) + { + spi_disable_cache(0); +# ifdef CONFIG_SMP + spi_disable_cache(1); +# endif + } +# endif /* CONFIG_ESP32_SPIFLASH */ + + return regs; } +#else +# ifdef CONFIG_ESP32_SPIFLASH + UNUSED(is_cache_reenabled); +# endif #endif + /* xtensa_user_panic never returns. */ xtensa_user_panic(exccause, regs); diff --git a/arch/xtensa/src/esp32s3/esp32s3_spiflash.c b/arch/xtensa/src/esp32s3/esp32s3_spiflash.c index 9ea87609fe0b7..bf86049c8be48 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_spiflash.c +++ b/arch/xtensa/src/esp32s3/esp32s3_spiflash.c @@ -251,26 +251,6 @@ static void spiflash_suspend_cache(void) g_spi_flash_cache_suspended = true; } -/**************************************************************************** - * Name: spiflash_resume_cache - * - * Description: - * Resume CPU cache. - * - ****************************************************************************/ - -static void spiflash_resume_cache(void) -{ - int cpu = this_cpu(); -#ifdef CONFIG_SMP - int other_cpu = cpu ? 0 : 1; -#endif - - spi_flash_restore_cache(); - - g_spi_flash_cache_suspended = false; -} - /**************************************************************************** * Name: spiflash_start * @@ -926,6 +906,32 @@ static int spiflash_init_spi_flash_op_block_task(int cpu) * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: spiflash_resume_cache + * + * Description: + * Resume CPU cache. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void spiflash_resume_cache(void) +{ + int cpu = this_cpu(); +#ifdef CONFIG_SMP + int other_cpu = cpu ? 0 : 1; +#endif + + spi_flash_restore_cache(); + + g_spi_flash_cache_suspended = false; +} + /**************************************************************************** * Name: esp32s3_mmap * diff --git a/arch/xtensa/src/esp32s3/esp32s3_spiflash.h b/arch/xtensa/src/esp32s3/esp32s3_spiflash.h index b2ad799529aba..044c702311334 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_spiflash.h +++ b/arch/xtensa/src/esp32s3/esp32s3_spiflash.h @@ -75,6 +75,22 @@ struct spiflash_map_req_s * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: spiflash_resume_cache + * + * Description: + * Resume CPU cache. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void spiflash_resume_cache(void); + /**************************************************************************** * Name: esp32s3_mmap * diff --git a/arch/xtensa/src/esp32s3/esp32s3_user.c b/arch/xtensa/src/esp32s3/esp32s3_user.c index d263bee055255..d15f0f748d5ae 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_user.c +++ b/arch/xtensa/src/esp32s3/esp32s3_user.c @@ -27,6 +27,10 @@ #include #include "xtensa.h" +#ifdef CONFIG_ESP32S3_SPIFLASH +#include "rom/esp32s3_spiflash.h" +#include "esp32s3_spiflash.h" +#endif /**************************************************************************** * Public Data @@ -61,6 +65,13 @@ uint32_t *xtensa_user(int exccause, uint32_t *regs) { +#ifdef CONFIG_ESP32S3_SPIFLASH + if (!spi_flash_cache_enabled()) + { + spiflash_resume_cache(); + } +#endif /* CONFIG_ESP32S3_SPIFLASH */ + /* xtensa_user_panic never returns. */ xtensa_user_panic(exccause, regs); From 54954e55b5d5004c1c14f84704168036e20886b1 Mon Sep 17 00:00:00 2001 From: Michal Lenc Date: Tue, 18 Feb 2025 10:37:14 +0100 Subject: [PATCH 32/33] samv7/pwm: fix incorrect write of CMRx register DTE (dead time enable) is the 17th bit in CMRx (channel mode) register. Function pwm_set_polarity did however read and write this register as 16 bit large, therefore dead time generation was always disabled. This fixes the issue, pwm_set_polarity now reads the register as 32 large. Also set the initial value of CMRx correctly in pwm_setup(). Signed-off-by: Michal Lenc --- arch/arm/src/samv7/sam_pwm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/src/samv7/sam_pwm.c b/arch/arm/src/samv7/sam_pwm.c index a7f196dbc7fba..23101e3f63b0e 100644 --- a/arch/arm/src/samv7/sam_pwm.c +++ b/arch/arm/src/samv7/sam_pwm.c @@ -765,7 +765,7 @@ static void pwm_set_polarity(struct pwm_lowerhalf_s *dev, uint8_t channel, uint8_t cpol, uint8_t dcpol) { struct sam_pwm_s *priv = (struct sam_pwm_s *)dev; - uint16_t regval; + uint32_t regval; /* Can't change polarity, if the channel is enabled! */ @@ -844,11 +844,11 @@ static int pwm_setup(struct pwm_lowerhalf_s *dev) channel = priv->channels[i].channel; #ifdef CONFIG_PWM_DEADTIME - regval |= CMR_DTE; + pwm_putreg(priv, SAMV7_PWM_CMRX + (channel * CHANNEL_OFFSET), CMR_DTE); +#else + pwm_putreg(priv, SAMV7_PWM_CMRX + (channel * CHANNEL_OFFSET), 0); #endif - pwm_putreg(priv, SAMV7_PWM_CMRX + (channel * CHANNEL_OFFSET), regval); - /* Reset duty cycle register */ pwm_putreg(priv, SAMV7_PWM_CDTYX + (channel * CHANNEL_OFFSET), 0); From 425ddc7f72c5ab71c715aace67de2c804992c4f8 Mon Sep 17 00:00:00 2001 From: Michal Lenc Date: Mon, 17 Feb 2025 15:03:27 +0100 Subject: [PATCH 33/33] lcd/st7789: fix incorrect buffer count for 3 wire RAM write If st7789_wrram is called with count = 1, then the entire buffer should be sent. However, in 3 wire mode, the driver has to send the buffer row by row because of additional data flag. The number of rows (count) can't be ST7789_YRES in this case, but only the number of rows in the buffer (this is write size / row size , where row size is ST7789_XRES * ST7789_BYTESPP). This also applies only if we want to write size larger than row size, because st7789_putrun allows to write just a part of a row. This fixes the incorrect behavior of the display in 3 wire mode if the display is split into more buffer writes (as in LCD driver for example, FB driver did not face this issue). Signed-off-by: Michal Lenc Co-authored-by: Martin Krasula --- drivers/lcd/st7789.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/lcd/st7789.c b/drivers/lcd/st7789.c index e69fb0e2cf81b..30af6905ea897 100644 --- a/drivers/lcd/st7789.c +++ b/drivers/lcd/st7789.c @@ -584,19 +584,22 @@ static void st7789_wrram(FAR struct st7789_dev_s *dev, size_t i; #ifdef CONFIG_LCD_ST7789_3WIRE size_t j; + size_t rowsiz; #endif st7789_sendcmd(dev, ST7789_RAMWR); #ifdef CONFIG_LCD_ST7789_3WIRE - if (count == 1) + rowsiz = ST7789_XRES * ST7789_BYTESPP; + + if (count == 1 && size > rowsiz) { /* We cannot send the entire buffer at once, split it to * separate rows. */ - count = ST7789_YRES; - size = ST7789_XRES * ST7789_BYTESPP; + count = size / rowsiz; + size = rowsiz; } st7789_select(dev->spi, LCD_ST7789_SPI_BITS); @@ -607,7 +610,7 @@ static void st7789_wrram(FAR struct st7789_dev_s *dev, { /* Copy data to rowbuff and add 9th bit */ - for (j = 0; j < ST7789_XRES * ST7789_BYTESPP; j += 2) + for (j = 0; j < size; j += 2) { /* Take care of correct byte order. */