diff --git a/devices/flash-mcxn94x/Makefile b/devices/flash-mcxn94x/Makefile new file mode 100644 index 00000000..d53c98da --- /dev/null +++ b/devices/flash-mcxn94x/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for flash-mcxn94x +# +# Copyright 2024 Phoenix Systems +# +# %LICENSE% +# + +OBJS += $(addprefix $(PREFIX_O)devices/flash-mcxn94x/, flash.o) diff --git a/devices/flash-mcxn94x/flash.c b/devices/flash-mcxn94x/flash.c new file mode 100644 index 00000000..3bf90913 --- /dev/null +++ b/devices/flash-mcxn94x/flash.c @@ -0,0 +1,157 @@ +/* + * Phoenix-RTOS + * + * plo - operating system loader + * + * MCX N94x Flash driver + * + * Copyright 2020, 2024 Phoenix Systems + * Author: Aleksander Kaminski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include +#include +#include + + +#define FLASH_NO 2 + + +static const struct { + u32 start; + u32 end; +} flashParams[FLASH_NO] = { + { FLASH_PROGRAM_1_ADDR, FLASH_PROGRAM_1_ADDR + FLASH_PROGRAM_BANK_SIZE }, + { FLASH_PROGRAM_2_ADDR, FLASH_PROGRAM_2_ADDR + FLASH_PROGRAM_BANK_SIZE } +}; + + +static int flashdrv_isValidAddress(unsigned int minor, u32 off, size_t size) +{ + size_t fsize = flashParams[minor].end - flashParams[minor].start; + + if ((off < fsize) && ((off + size) <= fsize)) { + return 1; + } + + return 0; +} + + +static int flashdrv_isValidMinor(unsigned int minor) +{ + return minor < FLASH_NO ? 1 : 0; +} + + +/* Device interface */ +static ssize_t flashdrv_read(unsigned int minor, addr_t offs, void *buff, size_t len, time_t timeout) +{ + char *memptr; + ssize_t ret = -EINVAL; + + (void)timeout; + + if ((flashdrv_isValidMinor(minor) != 0) && (flashdrv_isValidAddress(minor, offs, len) != 0)) { + memptr = (void *)flashParams[minor].start; + + hal_memcpy(buff, memptr + offs, len); + ret = (ssize_t)len; + } + + return ret; +} + + +static ssize_t flashdrv_write(unsigned int minor, addr_t offs, const void *buff, size_t len) +{ + /* Not supported. TODO? */ + return -ENOSYS; +} + + +static int flashdrv_done(unsigned int minor) +{ + if (flashdrv_isValidMinor(minor) == 0) { + return -EINVAL; + } + + /* Nothing to do */ + + return EOK; +} + + +static int flashdrv_sync(unsigned int minor) +{ + if (flashdrv_isValidMinor(minor) == 0) { + return -EINVAL; + } + + /* Nothing to do */ + + return EOK; +} + + +static int flashdrv_map(unsigned int minor, addr_t addr, size_t sz, int mode, addr_t memaddr, size_t memsz, int memmode, addr_t *a) +{ + size_t fSz; + addr_t fStart; + + if (flashdrv_isValidMinor(minor) == 0) { + return -EINVAL; + } + + fStart = flashParams[minor].start; + fSz = flashParams[minor].end - flashParams[minor].start; + *a = fStart; + + /* Check if region is located on flash */ + if ((addr + sz) >= fSz) { + return -EINVAL; + } + + /* Check if flash is mappable to map region */ + if ((fStart <= memaddr) && ((fStart + fSz) >= (memaddr + memsz))) { + return dev_isMappable; + } + + /* Device mode cannot be higher than map mode to copy data */ + if ((mode & memmode) != mode) { + return -EINVAL; + } + + /* Data can be copied from device to map */ + return dev_isNotMappable; +} + + +static int flashdrv_init(unsigned int minor) +{ + if (flashdrv_isValidMinor(minor) == 0) { + return -EINVAL; + } + + return EOK; +} + + +__attribute__((constructor)) static void flashdrv_reg(void) +{ + static const dev_handler_t h = { + .init = flashdrv_init, + .done = flashdrv_done, + .read = flashdrv_read, + .write = flashdrv_write, + .erase = NULL, /* TODO */ + .sync = flashdrv_sync, + .map = flashdrv_map + }; + + devs_register(DEV_STORAGE, FLASH_NO, &h); +} diff --git a/devices/uart-mcxn94x/Makefile b/devices/uart-mcxn94x/Makefile new file mode 100644 index 00000000..30725ac5 --- /dev/null +++ b/devices/uart-mcxn94x/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for uart-mcxn94x +# +# Copyright 2024 Phoenix Systems +# +# %LICENSE% +# + +OBJS += $(addprefix $(PREFIX_O)devices/uart-mcxn94x/, uart.o) diff --git a/devices/uart-mcxn94x/uart.c b/devices/uart-mcxn94x/uart.c new file mode 100644 index 00000000..a1032ea5 --- /dev/null +++ b/devices/uart-mcxn94x/uart.c @@ -0,0 +1,435 @@ +/* + * Phoenix-RTOS + * + * Operating system loader + * + * MCX N94x Serial driver + * + * Copyright 2020, 2024 Phoenix Systems + * Author: Hubert BuczyƄski, Aleksander Kaminski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include + +#include +#include +#include + +#define BUFFER_SIZE 0x200 + +typedef struct { + volatile u32 *base; + unsigned int irq; + + u16 rxFifoSz; + u16 txFifoSz; + + u8 rxBuff[BUFFER_SIZE]; + volatile u16 rxHead; + volatile u16 rxTail; + + u8 txBuff[BUFFER_SIZE]; + volatile u16 txHead; + volatile u16 txTail; + volatile u8 tFull; +} uart_t; + + +static struct { + uart_t uarts[UART_MAX_CNT]; + int init; +} uart_common; + + +/* clang-format off */ +enum { veridr = 0, paramr, globalr, pincfgr, baudr, statr, ctrlr, datar, matchr, modirr, fifor, waterr }; +/* clang-format on */ + + +static const u32 fifoSzLut[] = { 1, 4, 8, 16, 32, 64, 128, 256 }; + + +/* clang-format off */ +const int uartLut[] = { + (FLEXCOMM0_SEL == FLEXCOMM_UART) || (FLEXCOMM0_SEL == FLEXCOMM_UARTI2C), + (FLEXCOMM1_SEL == FLEXCOMM_UART) || (FLEXCOMM1_SEL == FLEXCOMM_UARTI2C), + (FLEXCOMM2_SEL == FLEXCOMM_UART) || (FLEXCOMM2_SEL == FLEXCOMM_UARTI2C), + (FLEXCOMM3_SEL == FLEXCOMM_UART) || (FLEXCOMM3_SEL == FLEXCOMM_UARTI2C), + (FLEXCOMM4_SEL == FLEXCOMM_UART) || (FLEXCOMM4_SEL == FLEXCOMM_UARTI2C), + (FLEXCOMM5_SEL == FLEXCOMM_UART) || (FLEXCOMM5_SEL == FLEXCOMM_UARTI2C), + (FLEXCOMM6_SEL == FLEXCOMM_UART) || (FLEXCOMM6_SEL == FLEXCOMM_UARTI2C), + (FLEXCOMM7_SEL == FLEXCOMM_UART) || (FLEXCOMM7_SEL == FLEXCOMM_UARTI2C), + (FLEXCOMM8_SEL == FLEXCOMM_UART) || (FLEXCOMM8_SEL == FLEXCOMM_UARTI2C), + (FLEXCOMM9_SEL == FLEXCOMM_UART) || (FLEXCOMM9_SEL == FLEXCOMM_UARTI2C) +}; + + +static const struct { + volatile u32 *base; + int tx; + int rx; + int txalt; + int rxalt; + int irq; +} info[10] = { + { .base = FLEXCOMM0_BASE, .tx = UART0_TX_PIN, .rx = UART0_RX_PIN, .txalt = UART0_TX_ALT, .rxalt = UART0_RX_ALT, .irq = FLEXCOMM0_IRQ }, + { .base = FLEXCOMM1_BASE, .tx = UART1_TX_PIN, .rx = UART1_RX_PIN, .txalt = UART1_TX_ALT, .rxalt = UART1_RX_ALT, .irq = FLEXCOMM1_IRQ }, + { .base = FLEXCOMM2_BASE, .tx = UART2_TX_PIN, .rx = UART2_RX_PIN, .txalt = UART2_TX_ALT, .rxalt = UART2_RX_ALT, .irq = FLEXCOMM2_IRQ }, + { .base = FLEXCOMM3_BASE, .tx = UART3_TX_PIN, .rx = UART3_RX_PIN, .txalt = UART3_TX_ALT, .rxalt = UART3_RX_ALT, .irq = FLEXCOMM3_IRQ }, + { .base = FLEXCOMM4_BASE, .tx = UART4_TX_PIN, .rx = UART4_RX_PIN, .txalt = UART4_TX_ALT, .rxalt = UART4_RX_ALT, .irq = FLEXCOMM4_IRQ }, + { .base = FLEXCOMM5_BASE, .tx = UART5_TX_PIN, .rx = UART5_RX_PIN, .txalt = UART5_TX_ALT, .rxalt = UART5_RX_ALT, .irq = FLEXCOMM5_IRQ }, + { .base = FLEXCOMM6_BASE, .tx = UART6_TX_PIN, .rx = UART6_RX_PIN, .txalt = UART6_TX_ALT, .rxalt = UART6_RX_ALT, .irq = FLEXCOMM6_IRQ }, + { .base = FLEXCOMM7_BASE, .tx = UART7_TX_PIN, .rx = UART7_RX_PIN, .txalt = UART7_TX_ALT, .rxalt = UART7_RX_ALT, .irq = FLEXCOMM7_IRQ }, + { .base = FLEXCOMM8_BASE, .tx = UART8_TX_PIN, .rx = UART8_RX_PIN, .txalt = UART8_TX_ALT, .rxalt = UART8_RX_ALT, .irq = FLEXCOMM8_IRQ }, + { .base = FLEXCOMM9_BASE, .tx = UART9_TX_PIN, .rx = UART9_RX_PIN, .txalt = UART9_TX_ALT, .rxalt = UART9_RX_ALT, .irq = FLEXCOMM9_IRQ }, +}; +/* clang-format on */ + + +/* TODO: temporary solution, it should be moved to device tree */ +static uart_t *uart_getInstance(unsigned int minor) +{ + if (minor >= UART_MAX_CNT) { + return NULL; + } + + if (uartLut[minor] == 0) { + return NULL; + } + + return &uart_common.uarts[minor]; +} + + +static int uart_getRXcount(uart_t *uart) +{ + return (*(uart->base + waterr) >> 24) & 0xff; +} + + +static int uart_getTXcount(uart_t *uart) +{ + return (*(uart->base + waterr) >> 8) & 0xff; +} + + +static int uart_handleIntr(unsigned int irq, void *buff) +{ + uart_t *uart = (uart_t *)buff; + + if (uart == NULL) { + return 0; + } + + /* Receive */ + while (uart_getRXcount(uart) != 0) { + uart->rxBuff[uart->rxHead] = *(uart->base + datar); + uart->rxHead = (uart->rxHead + 1) % BUFFER_SIZE; + if (uart->rxHead == uart->rxTail) { + uart->rxTail = (uart->rxTail + 1) % BUFFER_SIZE; + } + } + + /* Transmit */ + while (uart_getTXcount(uart) < uart->txFifoSz) { + if ((uart->txHead + 1) % BUFFER_SIZE != uart->txTail) { + uart->txHead = (uart->txHead + 1) % BUFFER_SIZE; + *(uart->base + datar) = uart->txBuff[uart->txHead]; + uart->tFull = 0; + } + else { + *(uart->base + ctrlr) &= ~(1 << 23); + break; + } + } + + return 0; +} + + +static u32 calculate_baudrate(int baud) +{ + int osr, sbr, bestSbr = 0, bestOsr = 0, bestErr = 1000, t; + + if (baud == 0) { + return 0; + } + + for (osr = 3; osr < 32; ++osr) { + sbr = UART_CLK / (baud * (osr + 1)); + sbr &= 0xfff; + t = UART_CLK / (sbr * (osr + 1)); + + if (t > baud) { + t = ((t - baud) * 1000) / baud; + } + else { + t = ((baud - t) * 1000) / baud; + } + + if (t < bestErr) { + bestErr = t; + bestOsr = osr; + bestSbr = sbr; + } + + /* Finish if error is < 1% */ + if (bestErr < 10) { + break; + } + } + + return (bestOsr << 24) | ((bestOsr <= 6) << 17) | bestSbr; +} + + +static void uart_initPins(unsigned int minor) +{ + _mcxn94x_portPinConfig(info[minor].rx, info[minor].rxalt, MCX_PIN_SLOW | MCX_PIN_WEAK | MCX_PIN_PULLUP_WEAK | MCX_PIN_INPUT_BUFFER_ENABLE); + _mcxn94x_portPinConfig(info[minor].tx, info[minor].txalt, MCX_PIN_SLOW | MCX_PIN_WEAK); +} + + +/* Device interface */ + +static ssize_t uart_read(unsigned int minor, addr_t offs, void *buff, size_t len, time_t timeout) +{ + uart_t *uart; + size_t l, cnt; + time_t start; + + uart = uart_getInstance(minor); + if (uart == NULL) { + return -EINVAL; + } + + start = hal_timerGet(); + while (uart->rxHead == uart->rxTail) { + if ((hal_timerGet() - start) >= timeout) { + return -ETIME; + } + } + hal_interruptsDisable(info[minor].irq); + + if (uart->rxHead > uart->rxTail) { + l = min(uart->rxHead - uart->rxTail, len); + } + else { + l = min(BUFFER_SIZE - uart->rxTail, len); + } + + hal_memcpy(buff, &uart->rxBuff[uart->rxTail], l); + cnt = l; + if ((len > l) && (uart->rxHead < uart->rxTail)) { + hal_memcpy((char *)buff + l, &uart->rxBuff[0], min(len - l, uart->rxHead)); + cnt += min(len - l, uart->rxHead); + } + uart->rxTail = ((uart->rxTail + cnt) % BUFFER_SIZE); + + hal_interruptsEnable(info[minor].irq); + + return cnt; +} + + +static ssize_t uart_write(unsigned int minor, const void *buff, size_t len) +{ + uart_t *uart; + size_t l, cnt = 0; + + uart = uart_getInstance(minor); + if (uart == NULL) { + return -EINVAL; + } + + while (uart->txHead == uart->txTail && uart->tFull) { + } + + hal_interruptsDisable(info[minor].irq); + if (uart->txHead > uart->txTail) { + l = min(uart->txHead - uart->txTail, len); + } + else { + l = min(BUFFER_SIZE - uart->txTail, len); + } + + hal_memcpy(&uart->txBuff[uart->txTail], buff, l); + cnt = l; + if ((len > l) && (uart->txTail >= uart->txHead)) { + hal_memcpy(uart->txBuff, (const char *)buff + l, min(len - l, uart->txHead)); + cnt += min(len - l, uart->txHead); + } + + /* Initialize sending */ + if (uart->txTail == uart->txHead) { + *(uart->base + datar) = uart->txBuff[uart->txHead]; + } + + uart->txTail = ((uart->txTail + cnt) % BUFFER_SIZE); + + if (uart->txTail == uart->txHead) { + uart->tFull = 1; + } + + *(uart->base + ctrlr) |= 1 << 23; + + hal_interruptsEnable(info[minor].irq); + + return cnt; +} + + +static ssize_t uart_safeWrite(unsigned int minor, addr_t offs, const void *buff, size_t len) +{ + ssize_t res; + size_t l; + + for (l = 0; l < len; l += res) { + res = uart_write(minor, (const char *)buff + l, len - l); + if (res < 0) { + return -ENXIO; + } + } + + return len; +} + + +static int uart_sync(unsigned int minor) +{ + uart_t *uart; + + uart = uart_getInstance(minor); + if (uart == NULL) { + return -EINVAL; + } + + /* Wait for transmission activity complete */ + while ((*(uart->base + statr) & (1 << 22)) == 0) { + } + + return EOK; +} + + +static int uart_done(unsigned int minor) +{ + uart_t *uart; + + uart = uart_getInstance(minor); + if (uart == NULL) { + return -EINVAL; + } + + uart_sync(minor); + + /* disable TX and RX */ + *(uart->base + ctrlr) &= ~((1 << 19) | (1 << 18)); + *(uart->base + ctrlr) &= ~((1 << 23) | (1 << 21)); + + hal_interruptsSet(uart->irq, NULL, NULL); + + return EOK; +} + + +static int uart_map(unsigned int minor, addr_t addr, size_t sz, int mode, addr_t memaddr, size_t memsz, int memmode, addr_t *a) +{ + if (minor >= UART_MAX_CNT) { + return -EINVAL; + } + + /* Device mode cannot be higher than map mode to copy data */ + if ((mode & memmode) != mode) { + return -EINVAL; + } + + /* uart is not mappable to any region */ + return dev_isNotMappable; +} + + +static int uart_init(unsigned int minor) +{ + u32 t; + uart_t *uart; + static const int baudrate[10] = { UART0_BAUDRATE, UART1_BAUDRATE, UART2_BAUDRATE, + UART3_BAUDRATE, UART4_BAUDRATE, UART5_BAUDRATE, UART6_BAUDRATE, UART7_BAUDRATE, + UART8_BAUDRATE, UART9_BAUDRATE }; + + uart = uart_getInstance(minor); + if (uart == NULL) { + return -EINVAL; + } + + if (uart_common.init == 0) { + uart_initPins(minor); + uart_common.init = 1; + } + + uart->base = info[minor].base; + + /* Disable TX and RX */ + *(uart->base + ctrlr) &= ~((1 << 19) | (1 << 18)); + + /* Reset all internal logic and registers, except the Global Register */ + *(uart->base + globalr) |= 1 << 1; + hal_cpuDataMemoryBarrier(); + *(uart->base + globalr) &= ~(1 << 1); + hal_cpuDataMemoryBarrier(); + + /* Disable input trigger */ + *(uart->base + pincfgr) &= ~3; + + /* Set 115200 default baudrate */ + t = *(uart->base + baudr) & ~((0x1f << 24) | (1 << 17) | 0xfff); + *(uart->base + baudr) = t | calculate_baudrate(baudrate[UART_CONSOLE]); + + /* Set 8 bit and no parity mode */ + *(uart->base + ctrlr) &= ~0x117; + + /* One stop bit */ + *(uart->base + baudr) &= ~(1 << 13); + + *(uart->base + waterr) = 0; + + /* Enable FIFO */ + *(uart->base + fifor) |= (1 << 7) | (1 << 3); + *(uart->base + fifor) |= 0x3 << 14; + + /* Clear all status flags */ + *(uart->base + statr) |= 0xc01fc000; + + uart->rxFifoSz = fifoSzLut[*(uart->base + fifor) & 0x7]; + uart->txFifoSz = fifoSzLut[(*(uart->base + fifor) >> 4) & 0x7]; + + /* Enable receiver interrupt */ + *(uart->base + ctrlr) |= 1 << 21; + + /* Enable TX and RX */ + *(uart->base + ctrlr) |= (1 << 19) | (1 << 18); + + hal_interruptsSet(info[minor].irq, uart_handleIntr, (void *)uart); + + return EOK; +} + + +__attribute__((constructor)) static void uart_reg(void) +{ + static const dev_handler_t h = { + .init = uart_init, + .done = uart_done, + .read = uart_read, + .write = uart_safeWrite, + .erase = NULL, + .sync = uart_sync, + .map = uart_map, + }; + + devs_register(DEV_UART, UART_MAX_CNT, &h); +} diff --git a/hal/armv8m/Makefile b/hal/armv8m/Makefile index 57951714..ad2f04f8 100644 --- a/hal/armv8m/Makefile +++ b/hal/armv8m/Makefile @@ -8,6 +8,8 @@ ifneq (, $(findstring nrf, $(TARGET_SUBFAMILY))) include hal/armv8m/nrf/Makefile +else ifneq (, $(findstring mcx, $(TARGET_SUBFAMILY))) + include hal/armv8m/mcx/Makefile endif OBJS += $(addprefix $(PREFIX_O)hal/$(TARGET_SUFF)/, cpu.o interrupts.o mpu.o string.o) diff --git a/hal/armv8m/interrupts.c b/hal/armv8m/interrupts.c index 5ed85f9a..f66fea02 100644 --- a/hal/armv8m/interrupts.c +++ b/hal/armv8m/interrupts.c @@ -103,7 +103,7 @@ int hal_interruptsSet(unsigned int irq, int (*isr)(unsigned int, void *), void * interrupts_nvicSetIRQ(irq - 16, 0); } else { - interrupts_nvicSetPriority(irq - 16, 0); + interrupts_nvicSetPriority(irq - 16, 1); interrupts_nvicSetIRQ(irq - 16, 1); } } diff --git a/hal/armv8m/mcx/Makefile b/hal/armv8m/mcx/Makefile new file mode 100644 index 00000000..0af9b872 --- /dev/null +++ b/hal/armv8m/mcx/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for Phoenix-RTOS loader (ARMv8M HAL mcx) +# +# Copyright 2022, 2024 Phoenix Systems +# +# %LICENSE% +# + +include hal/armv8m/mcx/n94x/Makefile +CFLAGS += -Ihal/armv8m/mcx/n94x +OBJS += $(addprefix $(PREFIX_O)hal/$(TARGET_SUFF)/mcx/, hal.o) diff --git a/hal/armv8m/mcx/hal.c b/hal/armv8m/mcx/hal.c new file mode 100644 index 00000000..90e8f87e --- /dev/null +++ b/hal/armv8m/mcx/hal.c @@ -0,0 +1,196 @@ +/* + * Phoenix-RTOS + * + * Operating system loader + * + * Hardware Abstraction Layer + * + * Copyright 2020-2022 Phoenix Systems + * Author: Hubert Buczynski, Marcin Baran, Gerard Swiderski, Aleksander Kaminski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include + +static struct { + hal_syspage_t *hs; + addr_t entry; +} hal_common; + + +/* Linker symbols */ +extern char __init_start[], __init_end[]; +extern char __text_start[], __etext[]; +extern char __rodata_start[], __rodata_end[]; +extern char __init_array_start[], __init_array_end[]; +extern char __fini_array_start[], __fini_array_end[]; +extern char __ramtext_start[], __ramtext_end[]; +extern char __data_start[], __data_end[]; +extern char __bss_start[], __bss_end[]; +extern char __heap_base[], __heap_limit[]; +extern char __stack_top[], __stack_limit[]; + +/* Timer */ +extern void timer_init(void); +extern void timer_done(void); + +/* Console */ +extern void console_init(void); + +/* Interrupts */ +extern void interrupts_init(void); + + +void hal_init(void) +{ + hal_cpuInit(); + + _mcxn94x_init(); + interrupts_init(); + + mpu_init(); + timer_init(); + console_init(); + + hal_common.entry = (addr_t)-1; +} + + +void hal_done(void) +{ + timer_done(); +} + + +void hal_syspageSet(hal_syspage_t *hs) +{ + hal_common.hs = hs; +} + + +const char *hal_cpuInfo(void) +{ + return "Cortex-M33 MCXN94x"; +} + + +addr_t hal_kernelGetAddress(addr_t addr) +{ + return addr; +} + + +void hal_kernelGetEntryPointOffset(addr_t *off, int *indirect) +{ + *off = sizeof(unsigned); + *indirect = 1; +} + + +void hal_kernelEntryPoint(addr_t addr) +{ + hal_common.entry = addr; +} + + +int hal_memoryAddMap(addr_t start, addr_t end, u32 attr, u32 mapId) +{ + return mpu_regionAlloc(start, end, attr, mapId, 1); +} + + +static void hal_getMinOverlappedRange(addr_t start, addr_t end, mapent_t *entry, mapent_t *minEntry) +{ + if ((start < entry->end) && (end > entry->start)) { + if (start > entry->start) { + entry->start = start; + } + + if (end < entry->end) { + entry->end = end; + } + + if (entry->start < minEntry->start) { + minEntry->start = entry->start; + minEntry->end = entry->end; + minEntry->type = entry->type; + } + } +} + + +int hal_memoryGetNextEntry(addr_t start, addr_t end, mapent_t *entry) +{ + int i; + mapent_t tempEntry, minEntry; + + static const mapent_t entries[] = { + { .start = (addr_t)__init_start, .end = (addr_t)__init_end, .type = hal_entryTemp }, + { .start = (addr_t)__text_start, .end = (addr_t)__etext, .type = hal_entryTemp }, + { .start = (addr_t)__rodata_start, .end = (addr_t)__rodata_end, .type = hal_entryTemp }, + { .start = (addr_t)__init_array_start, .end = (addr_t)__init_array_end, .type = hal_entryTemp }, + { .start = (addr_t)__fini_array_start, .end = (addr_t)__fini_array_end, .type = hal_entryTemp }, + { .start = (addr_t)__ramtext_start, .end = (addr_t)__ramtext_end, .type = hal_entryTemp }, + { .start = (addr_t)__data_start, .end = (addr_t)__data_end, .type = hal_entryTemp }, + { .start = (addr_t)__bss_start, .end = (addr_t)__bss_end, .type = hal_entryTemp }, + { .start = (addr_t)__heap_base, .end = (addr_t)__heap_limit, .type = hal_entryTemp }, + { .start = (addr_t)__stack_limit, .end = (addr_t)__stack_top, .type = hal_entryTemp }, + }; + + if (start == end) { + return -1; + } + + minEntry.start = (addr_t)-1; + minEntry.end = 0; + minEntry.type = 0; + + /* Syspage entry */ + tempEntry.start = (addr_t)hal_common.hs; + tempEntry.end = (addr_t)__heap_limit; + tempEntry.type = hal_entryReserved; + hal_getMinOverlappedRange(start, end, &tempEntry, &minEntry); + + for (i = 0; i < sizeof(entries) / sizeof(entries[0]); ++i) { + if (entries[i].start >= entries[i].end) { + continue; + } + tempEntry.start = entries[i].start; + tempEntry.end = entries[i].end; + tempEntry.type = entries[i].type; + hal_getMinOverlappedRange(start, end, &tempEntry, &minEntry); + } + + if (minEntry.start != (addr_t)-1) { + entry->start = minEntry.start; + entry->end = minEntry.end; + entry->type = minEntry.type; + + return 0; + } + + return -1; +} + + +int hal_cpuJump(void) +{ + if (hal_common.entry == (addr_t)-1) { + return -1; + } + + hal_interruptsDisableAll(); + + mpu_getHalData(hal_common.hs); + + /* clang-format off */ + __asm__ volatile("mov r9, %1; \ + bx %0" + : + : "r"(hal_common.entry), "r"((addr_t)hal_common.hs)); + /* clang-format on */ + __builtin_unreachable(); +} diff --git a/hal/armv8m/mcx/n94x/Makefile b/hal/armv8m/mcx/n94x/Makefile new file mode 100644 index 00000000..8111412c --- /dev/null +++ b/hal/armv8m/mcx/n94x/Makefile @@ -0,0 +1,20 @@ +# +# Makefile for Phoenix-RTOS loader (ARMv8M HAL mcxn94x) +# +# Copyright 2024 Phoenix Systems +# +# %LICENSE% +# + +LDFLAGS := $(filter-out -Tbss% , $(LDFLAGS)) +LDFLAGS := $(filter-out -Tdata% , $(LDFLAGS)) + +CFLAGS := $(filter-out -mfloat-abi% , $(CFLAGS)) +CFLAGS += -mfloat-abi=soft + +PLO_COMMANDS ?= alias app blob call console copy dump echo go help kernel kernelimg map mem phfs \ + reboot script wait + +PLO_ALLDEVICES := uart-mcxn94x flash-mcxn94x ram-storage + +OBJS += $(addprefix $(PREFIX_O)hal/$(TARGET_SUFF)/mcx/n94x/, _init.o n94x.o timer.o console.o) diff --git a/hal/armv8m/mcx/n94x/_init.S b/hal/armv8m/mcx/n94x/_init.S new file mode 100644 index 00000000..f135934c --- /dev/null +++ b/hal/armv8m/mcx/n94x/_init.S @@ -0,0 +1,96 @@ +/* + * Phoenix-RTOS + * + * plo - operating system loader + * + * Low-level initialization for Cortex-M33 (ARMv8) architecture + * + * Copyright 2012, 2016-2017, 2020-2022, 2024 Phoenix Systems + * Author: Jacek Popko, Pawel Pisarczyk, Jakub Sejdak, Aleksander Kaminski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#define __ASSEMBLY__ + +#include "config.h" + +.syntax unified + +.section .init, "x" + +.globl _init_vectors +.type _init_vectors, %object +_init_vectors: +.word _stack +.word _start + +.word _exceptions_dispatch /* NMI */ +.word _exceptions_dispatch /* HardFault */ +.word _exceptions_dispatch /* MemMgtFault */ +.word _exceptions_dispatch /* BusFault */ +.word _exceptions_dispatch /* UsageFault */ +.word _exceptions_dispatch /* SecureFault */ +.word 0 +.word 0 +.word 0 +.word 0 /* SVC */ +.word 0 /* Debug */ +.word 0 +.word _interrupts_dispatch /* PendSV */ +.word _interrupts_dispatch /* Systick */ + +.rept 156 /* Max number of ext interrupts - last peripheral id + 1 */ +.word _interrupts_dispatch /* _interrupts_dispatch */ +.endr +.size _init_vectors, .-_init_vectors + +.thumb +.thumb_func + +.globl _start +.type _start, %function +_start: + cpsid if + + /* Init vector table and stack pointer */ + ldr r0, =0xe000ed08 + ldr r1, =_init_vectors + str r1, [r0] + isb + dmb + + ldr r0, [r1] + bic r0, 7 + msr msp, r0 + ldr r8, =_startc + bx r8 +.size _start, .-_start +.ltorg + + +.globl _interrupts_dispatch +.type _interrupts_dispatch, %function +_interrupts_dispatch: + mrs r0, ipsr + stmdb sp!, {r0, r4-r11, lr} + bl hal_interruptDispatch + ldmia sp!, {r0, r4-r11, lr} + dmb + + bx lr +.size _interrupts_dispatch, .-_interrupts_dispatch +.ltorg + + +.globl _exceptions_dispatch +.type _exceptions_dispatch, %function + +_exceptions_dispatch: + cpsid if + /* TODO: implement exception dispatcher */ + 1: b 1b +.size _exceptions_dispatch, .-_exceptions_dispatch +.ltorg diff --git a/hal/armv8m/mcx/n94x/config.h b/hal/armv8m/mcx/n94x/config.h new file mode 100644 index 00000000..08b90cc9 --- /dev/null +++ b/hal/armv8m/mcx/n94x/config.h @@ -0,0 +1,40 @@ +/* + * Phoenix-RTOS + * + * plo - operating system loader + * + * Platform configuration file + * + * Copyright 2022, 2024 Phoenix Systems + * Author: Damian Loewnau, Aleksander Kaminski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#ifndef __ASSEMBLY__ + +#include "n94x.h" +#include "peripherals.h" +#include "hal/armv8m/mcx/types.h" + +#include +#include + +#include "hal/armv8m/cpu.h" +#include "hal/armv8m/mpu.h" + +#define PATH_KERNEL "phoenix-armv8m33-mcxn94x.elf" + +#endif + + +/* Import platform specific definitions */ +#include "ld/armv8m33-mcxn94x.ldt" + +#endif diff --git a/hal/armv8m/mcx/n94x/console.c b/hal/armv8m/mcx/n94x/console.c new file mode 100644 index 00000000..86e06a85 --- /dev/null +++ b/hal/armv8m/mcx/n94x/console.c @@ -0,0 +1,128 @@ +/* + * Phoenix-RTOS + * + * plo - operating system loader + * + * Console + * + * Copyright 2021-2023, 2024 Phoenix Systems + * Authors: Hubert Buczynski, Gerard Swiderski, Aleksander Kaminski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include +#include "n94x.h" +#include "config.h" +#include + + +/* clang-format off */ +enum { uart_verid = 0, uart_param, uart_global, uart_pincfg, uart_baud, + uart_stat, uart_ctrl, uart_data, uart_match, uart_modir, uart_fifo, + uart_water, uart_dataro, uart_mcr = 16, uart_msr, uart_reir, uart_teir, + uart_hdcr, uart_tocr = 22, uart_tosr, uart_timeoutn, uart_tcbrn = 128, + uart_tdbrn = 256 }; +/* clang-format on */ + + +static struct { + volatile u32 *base; + ssize_t (*writeHook)(int, const void *, size_t); +} halconsole_common; + + +void hal_consoleSetHooks(ssize_t (*writeHook)(int, const void *, size_t)) +{ + halconsole_common.writeHook = writeHook; +} + + +void hal_consolePrint(const char *s) +{ + const char *ptr; + + for (ptr = s; *ptr != '\0'; ++ptr) { + while ((*(halconsole_common.base + uart_stat) & (1uL << 23)) == 0uL) { + } + *(halconsole_common.base + uart_data) = *ptr; + } + + if (halconsole_common.writeHook != NULL) { + (void)halconsole_common.writeHook(0, s, ptr - s); + } +} + + +void console_init(void) +{ + u32 t; + /* clang-format off */ + static const struct { + volatile u32 *base; + int tx; + int rx; + int txalt; + int rxalt; + } info[10] = { + { .base = FLEXCOMM0_BASE, .tx = UART0_TX_PIN, .rx = UART0_RX_PIN, .txalt = UART0_TX_ALT, .rxalt = UART0_RX_ALT }, + { .base = FLEXCOMM1_BASE, .tx = UART1_TX_PIN, .rx = UART1_RX_PIN, .txalt = UART1_TX_ALT, .rxalt = UART1_RX_ALT }, + { .base = FLEXCOMM2_BASE, .tx = UART2_TX_PIN, .rx = UART2_RX_PIN, .txalt = UART2_TX_ALT, .rxalt = UART2_RX_ALT }, + { .base = FLEXCOMM3_BASE, .tx = UART3_TX_PIN, .rx = UART3_RX_PIN, .txalt = UART3_TX_ALT, .rxalt = UART3_RX_ALT }, + { .base = FLEXCOMM4_BASE, .tx = UART4_TX_PIN, .rx = UART4_RX_PIN, .txalt = UART4_TX_ALT, .rxalt = UART4_RX_ALT }, + { .base = FLEXCOMM5_BASE, .tx = UART5_TX_PIN, .rx = UART5_RX_PIN, .txalt = UART5_TX_ALT, .rxalt = UART5_RX_ALT }, + { .base = FLEXCOMM6_BASE, .tx = UART6_TX_PIN, .rx = UART6_RX_PIN, .txalt = UART6_TX_ALT, .rxalt = UART6_RX_ALT }, + { .base = FLEXCOMM7_BASE, .tx = UART7_TX_PIN, .rx = UART7_RX_PIN, .txalt = UART7_TX_ALT, .rxalt = UART7_RX_ALT }, + { .base = FLEXCOMM8_BASE, .tx = UART8_TX_PIN, .rx = UART8_RX_PIN, .txalt = UART8_TX_ALT, .rxalt = UART8_RX_ALT }, + { .base = FLEXCOMM9_BASE, .tx = UART9_TX_PIN, .rx = UART9_RX_PIN, .txalt = UART9_TX_ALT, .rxalt = UART9_RX_ALT }, + }; + static const int baud[10] = { UART0_BAUDRATE, UART1_BAUDRATE, UART2_BAUDRATE, UART3_BAUDRATE, UART4_BAUDRATE, + UART5_BAUDRATE, UART6_BAUDRATE, UART7_BAUDRATE, UART8_BAUDRATE, UART9_BAUDRATE }; + /* clang-format on */ + + halconsole_common.base = info[UART_CONSOLE].base; + + /* Configure RX and TX pins */ + _mcxn94x_portPinConfig(info[UART_CONSOLE].rx, info[UART_CONSOLE].rxalt, MCX_PIN_SLOW | MCX_PIN_WEAK | MCX_PIN_PULLUP_WEAK | MCX_PIN_INPUT_BUFFER_ENABLE); + _mcxn94x_portPinConfig(info[UART_CONSOLE].tx, info[UART_CONSOLE].txalt, MCX_PIN_SLOW | MCX_PIN_WEAK); + + /* Reset all internal logic and registers, except the Global Register */ + *(halconsole_common.base + uart_global) |= 1 << 1; + hal_cpuDataMemoryBarrier(); + *(halconsole_common.base + uart_global) &= ~(1 << 1); + hal_cpuDataMemoryBarrier(); + + /* Set baud rate */ + t = *(halconsole_common.base + uart_baud) & ~((0x1f << 24) | (1 << 17) | 0x1fff); + + /* For baud rate calculation, default UART_CLK=12MHz assumed */ + switch (baud[UART_CONSOLE]) { + case 9600: t |= 0x03020138; break; + case 19200: t |= 0x0302009c; break; + case 38400: t |= 0x0302004e; break; + case 57600: t |= 0x03020034; break; + case 230400: t |= 0x0302000d; break; + default: t |= 0x0302001a; break; /* 115200 */ + } + *(halconsole_common.base + uart_baud) = t; + + /* Set 8 bit and no parity mode */ + *(halconsole_common.base + uart_ctrl) &= ~0x117; + + /* One stop bit */ + *(halconsole_common.base + uart_baud) &= ~(1 << 13); + + *(halconsole_common.base + uart_water) = 0; + + /* Enable FIFO */ + *(halconsole_common.base + uart_fifo) |= (1 << 7) | (1 << 3); + *(halconsole_common.base + uart_fifo) |= 0x3 << 14; + + /* Clear all status flags */ + *(halconsole_common.base + uart_stat) |= 0xc01fc000; + + /* Enable TX and RX */ + *(halconsole_common.base + uart_ctrl) |= (1 << 19) | (1 << 18); +} diff --git a/hal/armv8m/mcx/n94x/n94x.c b/hal/armv8m/mcx/n94x/n94x.c new file mode 100644 index 00000000..d0c312c9 --- /dev/null +++ b/hal/armv8m/mcx/n94x/n94x.c @@ -0,0 +1,957 @@ +/* + * Phoenix-RTOS + * + * plo - operating system loader + * + * MCXN94x basic peripherals control functions + * + * Copyright 2024 Phoenix Systems + * Author: Aleksander Kaminski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include + +#include +#include +#include "n94x.h" + +#define LDO_VOUT_1V 2 +#define LDO_VOUT_1V05 3 +#define LDO_VOUT_1V1 4 +#define LDO_VOUT_1V15 5 +#define LDO_VOUT_1V2 6 +#define LDO_VOUT_1V25 7 + + +/* clang-format off */ +enum { flexcomm_istat = 1021, flexcomm_pselid }; + + +enum { + syscon_ahbmatprio = 4, syscon_cpu0stckcal = 14, syscon_cpu0nstckcal, syscon_cpu1stckcal, + syscon_nmisrc = 18, + syscon_presetctrl0 = 64, syscon_presetctrl1, syscon_presetctrl2, syscon_presetctrl3, + syscon_presetctrlset0 = 72, syscon_presetctrlset1, syscon_presetctrlset2, syscon_presetctrlset3, + syscon_presetctrlcrl0 = 80, syscon_presetctrlcrl1, syscon_presetctrlcrl2, syscon_presetctrlcrl3, + syscon_ahbclkctrl0 = 128, syscon_ahbclkctrl1, syscon_ahbclkctrl2, syscon_ahbclkctrl3, + syscon_ahbclkctrlset0 = 136, syscon_ahbclkctrlset1, syscon_ahbclkctrlset2, syscon_ahbclkctrlset3, + syscon_ahbclkctrlclr0 = 144, syscon_ahbclkctrlclr1, syscon_ahbclkctrlclr2, syscon_ahbclkctrlclr3, + syscon_systickclksel0 = 152, syscon_systickclksel1, syscon_tracesel, + syscon_ctimer0clksel, syscon_ctimer1clksel, syscon_ctimer2clksel, syscon_ctimer3clksel, + syscon_ctimer4clksel, syscon_clkoutset = 162, syscon_adc0clksel = 169, syscon_usb0clksel, + syscon_fc0clksel = 172, syscon_fc1clksel, syscon_fc2clksel, syscon_fc3clksel, syscon_fc4clksel, + syscon_fc5clksel, syscon_fc6clksel, syscon_fc7clksel, syscon_fc8clksel, syscon_fc9clksel, + syscon_sctclksel = 188, syscon_systickclkdiv0 = 192, syscon_systickclkdiv1, syscon_traceclkdiv, + syscon_tsiclksel = 212, syscon_sincfiltclksel = 216, syscon_slowclkdiv = 222, syscon_tsiclkdiv, + syscon_ahbclkdiv, syscon_clkoutdiv, syscon_frohfdiv, syscon_wdt0clkdiv, syscon_adc0clkdiv = 229, + syscon_usb0clkdiv, syscon_sctclkdiv = 237, syscon_pllclkdiv = 241, syscon_ctimer0clkdiv = 244, + syscon_ctimer1clkdiv, syscon_ctimer2clkdiv, syscon_ctimer3clkdiv, syscon_ctimer4clkdiv, + syscon_pll1clk0div, syscon_pll1clk1div, syscon_clkunlock, syscon_nvmctrl, syscon_romcr, + syscon_smartdmaint = 261, syscon_adc1clksel = 281, syscon_adc1clkdiv, syscon_dac0clksel = 292, + syscon_dac0clkdiv, syscon_dac1clksel, syscon_dac1clkdiv, syscon_dac2clksel, syscon_dac2clkdiv, + syscon_flexspiclksel, syscon_flexspiclkdiv, syscon_pllclkdivsel = 331, syscon_i3c0fclksel, + syscon_i3c0fclkstcsel, syscon_i3c0fclkstcdiv, syscon_i3c0fclksdiv, syscon_i3c0fclkdiv, syscon_i3c0fclkssel, + syscon_micfilfclksel, syscon_micfilfclkdiv, syscon_usdhcclksel = 342, syscon_usdhcclkdiv, + syscon_flexioclksel, syscon_flexioclkdiv, syscon_flexcan0clksel = 360, syscon_flexcan0clkdiv, + syscon_flexcan1clksel, syscon_flexcan1clkdiv, syscon_enetrmiiclksel, syscon_enetrmiiclkdiv, + syscon_enetptprefclksel, syscon_enetptprefclkdiv, syscon_enetphyintfsel, syscon_enetsbdflowctrl, + syscon_ewm0clksel = 373, syscon_wdt1clksel, syscon_wdt1clkdiv, syscon_ostimerclksel, + syscon_cmp0fclksel = 380, syscon_cmp0fclkdiv, syscon_cmp0rrclksel, syscon_rrclkdiv, + syscon_cmp1fclksel, syscon_cmp1fclkdiv, syscon_cmp1rrclksel, syscon_cmp1rrclkdiv, + syscon_cmp2fclksel, syscon_cmp2fclkdiv, syscon_cmp2rrclksel, syscon_cmp2rrclkdiv, + syscon_cpuctrl = 512, syscon_cpboot, syscon_cpustat = 514, syscon_lpcacctrl = 521, + syscon_flexcomm0clkdiv = 532, syscon_flexcomm1clkdiv, syscon_flexcomm2clkdiv, + syscon_flexcomm3clkdiv, syscon_flexcomm4clkdiv, syscon_flexcomm5clkdiv, syscon_flexcomm6clkdiv, + syscon_flexcomm7clkdiv, syscon_flexcomm8clkdiv, syscon_flexcomm9clkdiv, + syscon_sai0clksel = 544, syscon_sai1clksel, syscon_sai0clkdiv, syscon_sai1clkdiv, + syscon_emvsim0clksel, syscon_emvsim1clksel, syscon_emvsim0clkdiv, syscon_emvsim1clkdiv, + syscon_clockctrl = 646, syscon_i3c1fclksel = 716, syscon_i3c1fclkstcsel, syscon_i3c1fclkstcdiv, + syscon_i3c1fclksdiv, syscon_i3c1fclkdiv, syscon_i3c1fclkssel, syscon_etbstatus = 724, + syscon_etbcounterctrl, syscon_etbcounterreload, syscon_etbcountervalue, syscon_graycodelsb, + syscon_graycodemsb, syscon_binarycodelsb, syscon_binarycodemsb, syscon_autoclkgateoverride = 897, + syscon_autoclkgataoverridec = 907, syscon_pwm0subctl = 910, syscon_pwm1subctl, + syscon_ctimerglobalstarten, syscon_eccenablectrl, syscon_jtagid = 1020, syscon_devicetype, + syscon_deviceid0, syscon_dieid +}; + + +enum { + scg_verid = 0, scg_param, scg_trimlock, scg_csr = 4, scg_rccr, scg_sosccsr = 64, + scg_sosccfg = 66, scg_sirccsr = 128, scg_sirctcfg = 131, scg_sirctrim, scg_sircstat = 134, + scg_firccsr = 192, scg_firccfg = 194, scg_firctrim, scg_fircstat = 198, scg_rosccsr = 256, + scg_apllcsr = 320, scg_apllctrl, scg_apllstat, scg_apllndiv, scg_apllmdiv, scg_apllpdiv, + scg_aplllockcnfg, scg_apllsscgstat, scg_apllsscg0, scg_apllsscg1, scg_apllovrd = 381, + scg_spllcsr = 384, scg_spllctrl, scg_spllstat, scg_spllndiv, scg_spllmdiv, scg_spllpdiv, + scg_spllockcnfg, scg_spllsscgstat, scg_spllsscg0, scg_spllsscg1, scg_spllovrd = 445, + scg_upllcsr = 448, scg_ldocsr = 512 +}; + + +enum { + port_verid = 0, port_gpclr = 4, port_gpchr, port_config = 8, port_edfr = 16, port_edier, + port_edcr, port_calib0 = 24, port_calib1, port_pcr0 = 32, port_pcr1, port_pcr2, port_pcr3, + port_pcr4, port_pcr5, port_pcr6, port_pcr7, port_pcr8, port_pcr9, port_pcr10, port_pcr11, + port_pcr12, port_pcr13, port_pcr14, port_pcr15, port_pcr16, port_pcr17, port_pcr18, + port_pcr19, port_pcr20, port_pcr21, port_pcr22, port_pcr23, port_pcr24, port_pcr25, + port_pcr26, port_pcr27, port_pcr28, port_pcr29, port_pcr30, port_pcr31 +}; + + +enum { + inputmux_sct0inmux0 = 0, inputmux_sct0inmux1, inputmux_sct0inmux2, inputmux_sct0inmux3, + inputmux_sct0inmux4, inputmux_sct0inmux5, inputmux_sct0inmux6, inputmux_sct0inmux7, + inputmux_ctimer0cap0, inputmux_ctimer0cap1, inputmux_ctimer0cap2, inputmux_ctimer0cap3, + inputmux_timer0trig, inputmux_ctimer1cap0 = 16, inputmux_ctimer1cap1, inputmux_ctimer1cap2, + inputmux_ctimer1cap3, inputmux_timer1trig, inputmux_ctimer2cap0 = 24, inputmux_ctimer2cap1, + inputmux_ctimer2cap2, inputmux_ctimer2cap3, inputmux_timer2trig, inputmux_smartdmaarchbinmux0 = 40, + inputmux_smartdmaarchbinmux1, inputmux_smartdmaarchbinmux2, inputmux_smartdmaarchbinmux3, + inputmux_smartdmaarchbinmux4, inputmux_smartdmaarchbinmux5, inputmux_smartdmaarchbinmux6, + inputmux_smartdmaarchbinmux7, inputmux_pintsel0, inputmux_pintsel1, inputmux_pintsel2, + inputmux_pintsel3, inputmux_pintsel4, inputmux_pintsel5, inputmux_pintsel6, inputmux_pintsel7, + inputmux_freqmesref = 96, inputmux_freqmeastar, inputmux_ctimer3cap0 = 105, inputmux_ctimer3cap1, + inputmux_ctimer3cap2, inputmux_ctimer3cap3, inputmux_timer3trig, inputmux_ctimer4cap0 = 112, + inputmux_ctimer4cap1, inputmux_ctimer4cap2, inputmux_ctimer4cap3, inputmux_timer4trig, + inputmux_cmp0trig = 152, inputmux_adc0trig0 = 160, inputmux_adc0trig1, inputmux_adc0trig2, + inputmux_adc0trig3, inputmux_adc1trig0 = 176, inputmux_adc1trig1, inputmux_adc1trig2, + inputmux_adc1trig3, inputmux_dac0trig = 192, inputmux_dac1trig = 200, inputmux_dac2trig = 208, + inputmux_enc0trig = 216, inputmux_enc0home, inputmux_enc0index, inputmux_enc0phaseb, + inputmux_enc0phasea, inputmux_enc1trig = 224, inputmux_enc1home, inputmux_enc1index, + inputmux_enc1phaseb, inputmux_enc1phasea, inputmux_flexpwm0sm0extsync = 232, + inputmux_flexpwm0sm1extsync, inputmux_flexpwm0sm2extsync, inputmux_flexpwm0sm3extsync, + inputmux_flexpwm0sm0exta, inputmux_flexpwm0sm1exta, inputmux_flexpwm0sm2exta, + inputmux_flexpwm0sm3exta, inputmux_flexpwm0extforce, inputmux_flexpwm0fault0, + inputmux_flexpwm0fault1, inputmux_flexpwm0fault2, inputmux_flexpwm0fault3, + inputmux_flexpwm1sm0extsync = 248, inputmux_flexpwm1sm1extsync, inputmux_flexpwm1sm2extsync, + inputmux_flexpwm1sm3extsync, inputmux_flexpwm1sm0exta, inputmux_flexpwm1sm1exta, + inputmux_flexpwm1sm2exta, inputmux_flexpwm1sm3exta, inputmux_flexpwm1extforce, + inputmux_flexpwm1fault0, inputmux_flexpwm1fault1, inputmux_flexpwm1fault2, + inputmux_flexpwm1fault3, inputmux_pwm0extclk = 264, inputmux_pwm1extclk, + inputmux_evtgtrig0 = 272, inputmux_evtgtrig1, inputmux_evtgtrig2, inputmux_evtgtrig3, + inputmux_evtgtrig4, inputmux_evtgtrig5, inputmux_evtgtrig6, inputmux_evtgtrig7, + inputmux_evtgtrig8, inputmux_evtgtrig9, inputmux_evtgtrig10, inputmux_evtgtrig11, + inputmux_evtgtrig12, inputmux_evtgtrig13, inputmux_evtgtrig14, inputmux_evtgtrig15, + inputmux_usbfstrig, inputmux_tsitrig = 296, inputmux_exttrig0 = 304, inputmux_exttrig1, + inputmux_exttrig2, inputmux_exttrig3, inputmux_exttrig4, inputmux_exttrig5, inputmux_exttrig6, + inputmux_exttrig7, inputmux_cmp1trig = 312, inputmux_cmp2trig = 320, + inputmux_sincfilterch0 = 328, inputmux_sincfilterch1, inputmux_sincfilterch2, + inputmux_sincfilterch3, inputmux_sincfilterch4, inputmux_opamp0trig = 352, + inputmux_opamp1trig, inputmux_opamp2trig, inputmux_flexcomm0trig = 360, + inputmux_flexcomm1trig = 368, inputmux_flexcomm2trig = 376, inputmux_flexcomm3trig = 384, + inputmux_flexcomm4trig = 392, inputmux_flexcomm5trig = 400, inputmux_flexcomm6trig = 408, + inputmux_flexcomm7trig = 416, inputmux_flexcomm8trig = 424, inputmux_flexcomm9trig = 436, + inputmux_flexiotrig0 = 440, inputmux_flexiotrig1, inputmux_flexiotrig2, inputmux_flexiotrig3, + inputmux_flexiotrig4, inputmux_flexiotrig5, inputmux_flexiotrig6, inputmux_flexiotrig7, + inputmux_dma0reqenable0 = 448, inputmux_dma0reqenable0set, inputmux_dma0reqenable0clr, + inputmux_dma0reqenable0tog, inputmux_dma0reqenable1, inputmux_dma0reqenable1set, + inputmux_dma0reqenable1clr, inputmux_dma0reqenable1tog, inputmux_dma0reqenable2, + inputmux_dma0reqenable2set, inputmux_dma0reqenable2clr,inputmux_dma0reqenable2tog, + inputmux_dma0reqenable3, inputmux_dma0reqenable3set, inputmux_dma0reqenable3clr, + inputmux_dma1reqenable0 = 480, inputmux_dma1reqenable0set, inputmux_dma1reqenable0clr, + inputmux_dma1reqenable0tog, inputmux_dma1reqenable1, inputmux_dma1reqenable1set, + inputmux_dma1reqenable1clr, inputmux_dma1reqenable1tog, inputmux_dma1reqenable2, + inputmux_dma1reqenable2set, inputmux_dma1reqenable2clr, inputmux_dma1reqenable2tog, + inputmux_dma1reqenable3, inputmux_dma1reqenable3set, inputmux_dma1reqenable3clr +}; + + +enum { + vbat_verid = 0, vbat_statusa = 4, vbat_statusb, vbat_irqena, vbat_irqenb, vbat_wakena, + vbat_wakenb, vbat_wakecfg = 14, vbat_oscctla = 64, vbat_oscctlb, vbat_osccfga, + vbat_osccfgb, vbat_osclcka = 70, vbat_osclckb, vbat_oscclke, vbat_froctla = 128, + vbat_froctlb, vbat_frolcka = 134, vbat_frolckb, vbat_froclke, vbat_ldoctla = 192, + vbat_ldoctlb, vbat_ldolcka = 198, vbat_ldolckb, vbat_ldoramc, vbat_ldotimer0 = 204, + vbat_ldotimer1 = 206, vbat_wakeup0a = 448, vbat_wakeup0b, vbat_wakeup1a, vbat_wakeup1b, + vbat_waklcka = 510, vbat_waklckb +}; + + +enum { + spc_verid = 0, spc_sc = 4, spc_cntrl, spc_lpreqcfg = 7, spc_pdstatus0 = 12, spc_pdstatus1, + spc_sramctl = 16, spc_activecfg = 64, spc_activecgfg1, spc_lpcfg, spc_lpcfg1, spc_lpwkupdelay = 72, + spc_activevdelay, spc_vdstat = 76, spc_vdcorecfg, spc_vdsyscfg, spc_iocfg, spc_evdcfg, + spc_glitchdetectsc, spc_coreldocfg = 192, spc_sysldocfg = 256, spc_dcdccfg = 320, spc_dcdcburstcfg +}; + + +enum { + fmu_fstat = 0, fmu_fcnfg, fmu_fctlr, fmu_fcc0b0, fmu_fcc0b1, fmu_fcc0b2, fmu_fcc0b3, fmu_fcc0b4, + fmu_fcc0b5, fmu_fcc0b6, fmu_fcc0b7 +}; + + +enum { + itrc_status = 0, itrc_status1, itrc_outsel, itrc_outsel1 = 24, itrc_outsel2 = 46, + itrc_swevent0 = 94, itrc_swevent1 +}; + + +enum { + gdet_conf0 = 0, gdet_conf1, gdet_enable1, gdet_conf2, gdet_conf3, gdet_conf4, gdet_conf5, + gdet_reset = 4010, gdet_test, gdet_dlyctrl = 4016 +}; +/* clang-format on */ + + +static struct { + volatile u32 *port[6]; + volatile u32 *inputmux; + volatile u32 *syscon; + volatile u32 *flexcomm[10]; + volatile u32 *vbat; + volatile u32 *scg; + volatile u32 *spc; + volatile u32 *fmu; + volatile u32 *gdet0; + volatile u32 *gdet1; + volatile u32 *itrc; +} n94x_common; + + +int _mcxn94x_portPinConfig(int pin, int mux, int options) +{ + int port = pin / 32; + + pin %= 32; + + if (port >= (sizeof(n94x_common.port) / sizeof(*n94x_common.port))) { + return -EINVAL; + } + + *(n94x_common.port[port] + port_pcr0 + pin) = (((mux & 0xf) << 8) | (options & 0x307f)); + + return 0; +} + + +static int _mcxn94x_sysconGetRegs(int dev, volatile u32 **selr, volatile u32 **divr) +{ + if ((dev < pctl_rom) || (dev > pctl_i3c1stc)) { + return -1; + } + + *selr = NULL; + *divr = NULL; + + switch (dev) { + case pctl_flexspi: + *selr = n94x_common.syscon + syscon_flexspiclksel; + *divr = n94x_common.syscon + syscon_flexspiclkdiv; + break; + + case pctl_adc0: + *selr = n94x_common.syscon + syscon_adc0clksel; + *divr = n94x_common.syscon + syscon_adc0clkdiv; + break; + + case pctl_adc1: + *selr = n94x_common.syscon + syscon_adc1clksel; + *divr = n94x_common.syscon + syscon_adc1clkdiv; + break; + + case pctl_dac0: + *selr = n94x_common.syscon + syscon_dac0clksel; + *divr = n94x_common.syscon + syscon_dac0clkdiv; + break; + + case pctl_dac1: + *selr = n94x_common.syscon + syscon_dac1clksel; + *divr = n94x_common.syscon + syscon_dac1clkdiv; + break; + + case pctl_dac2: + *selr = n94x_common.syscon + syscon_dac2clksel; + *divr = n94x_common.syscon + syscon_dac2clkdiv; + break; + + case pctl_timer0: + *selr = n94x_common.syscon + syscon_ctimer0clksel; + *divr = n94x_common.syscon + syscon_ctimer0clkdiv; + break; + + case pctl_timer1: + *selr = n94x_common.syscon + syscon_ctimer1clksel; + *divr = n94x_common.syscon + syscon_ctimer1clkdiv; + break; + + case pctl_timer2: + *selr = n94x_common.syscon + syscon_ctimer2clksel; + *divr = n94x_common.syscon + syscon_ctimer2clkdiv; + break; + + case pctl_timer3: + *selr = n94x_common.syscon + syscon_ctimer3clksel; + *divr = n94x_common.syscon + syscon_ctimer3clkdiv; + break; + + case pctl_timer4: + *selr = n94x_common.syscon + syscon_ctimer4clksel; + *divr = n94x_common.syscon + syscon_ctimer4clkdiv; + break; + + case pctl_sct: + *selr = n94x_common.syscon + syscon_sctclksel; + *divr = n94x_common.syscon + syscon_sctclkdiv; + break; + + case pctl_ostimer: + *selr = n94x_common.syscon + syscon_ostimerclksel; + break; + + case pctl_ewm: + *selr = n94x_common.syscon + syscon_ewm0clksel; + break; + + case pctl_wwdt0: + *divr = n94x_common.syscon + syscon_wdt0clkdiv; + break; + + case pctl_wwdt1: + *selr = n94x_common.syscon + syscon_wdt1clksel; + *divr = n94x_common.syscon + syscon_wdt1clkdiv; + break; + + case pctl_usb0fs: + *selr = n94x_common.syscon + syscon_usb0clksel; + *divr = n94x_common.syscon + syscon_usb0clkdiv; + break; + + case pctl_evsim0: + *selr = n94x_common.syscon + syscon_emvsim0clksel; + *divr = n94x_common.syscon + syscon_emvsim0clkdiv; + break; + + case pctl_evsim1: + *selr = n94x_common.syscon + syscon_emvsim1clksel; + *divr = n94x_common.syscon + syscon_emvsim1clkdiv; + break; + + case pctl_cmp0: + *selr = n94x_common.syscon + syscon_cmp0fclksel; + *divr = n94x_common.syscon + syscon_cmp0fclkdiv; + break; + + case pctl_cmp1: + *selr = n94x_common.syscon + syscon_cmp1fclksel; + *divr = n94x_common.syscon + syscon_cmp1fclkdiv; + break; + + case pctl_cmp2: + *selr = n94x_common.syscon + syscon_cmp2fclksel; + *divr = n94x_common.syscon + syscon_cmp2fclkdiv; + break; + + case pctl_cmp0rr: + *selr = n94x_common.syscon + syscon_cmp0rrclksel; + break; + + case pctl_cmp1rr: + *selr = n94x_common.syscon + syscon_cmp1rrclksel; + break; + + case pctl_cmp2rr: + *selr = n94x_common.syscon + syscon_cmp2rrclksel; + break; + + case pctl_fc0: + *selr = n94x_common.syscon + syscon_fc0clksel; + *divr = n94x_common.syscon + syscon_flexcomm0clkdiv; + break; + + case pctl_fc1: + *selr = n94x_common.syscon + syscon_fc1clksel; + *divr = n94x_common.syscon + syscon_flexcomm1clkdiv; + break; + + case pctl_fc2: + *selr = n94x_common.syscon + syscon_fc2clksel; + *divr = n94x_common.syscon + syscon_flexcomm2clkdiv; + break; + + case pctl_fc3: + *selr = n94x_common.syscon + syscon_fc3clksel; + *divr = n94x_common.syscon + syscon_flexcomm3clkdiv; + break; + + case pctl_fc4: + *selr = n94x_common.syscon + syscon_fc4clksel; + *divr = n94x_common.syscon + syscon_flexcomm4clkdiv; + break; + + case pctl_fc5: + *selr = n94x_common.syscon + syscon_fc5clksel; + *divr = n94x_common.syscon + syscon_flexcomm5clkdiv; + break; + + case pctl_fc6: + *selr = n94x_common.syscon + syscon_fc6clksel; + *divr = n94x_common.syscon + syscon_flexcomm6clkdiv; + break; + + case pctl_fc7: + *selr = n94x_common.syscon + syscon_fc7clksel; + *divr = n94x_common.syscon + syscon_flexcomm7clkdiv; + break; + + case pctl_fc8: + *selr = n94x_common.syscon + syscon_fc8clksel; + *divr = n94x_common.syscon + syscon_flexcomm8clkdiv; + break; + + case pctl_fc9: + *selr = n94x_common.syscon + syscon_fc9clksel; + *divr = n94x_common.syscon + syscon_flexcomm9clkdiv; + break; + + case pctl_flexcan0: + *selr = n94x_common.syscon + syscon_flexcan0clksel; + *divr = n94x_common.syscon + syscon_flexcan0clkdiv; + break; + + case pctl_flexcan1: + *selr = n94x_common.syscon + syscon_flexcan1clksel; + *divr = n94x_common.syscon + syscon_flexcan1clkdiv; + break; + + case pctl_flexio: + *selr = n94x_common.syscon + syscon_flexioclksel; + *divr = n94x_common.syscon + syscon_flexioclkdiv; + break; + + case pctl_usdhc: + *selr = n94x_common.syscon + syscon_usdhcclksel; + *divr = n94x_common.syscon + syscon_usdhcclkdiv; + break; + + case pctl_sinc: + *selr = n94x_common.syscon + syscon_sincfiltclksel; + break; + + case pctl_i3c0: + *selr = n94x_common.syscon + syscon_i3c0fclksel; + *divr = n94x_common.syscon + syscon_i3c0fclkdiv; + break; + + case pctl_i3c1: + *selr = n94x_common.syscon + syscon_i3c1fclksel; + *divr = n94x_common.syscon + syscon_i3c1fclkdiv; + break; + + case pctl_i3c0s: + *selr = n94x_common.syscon + syscon_i3c0fclkssel; + *divr = n94x_common.syscon + syscon_i3c0fclksdiv; + break; + + case pctl_i3c1s: + *selr = n94x_common.syscon + syscon_i3c1fclkssel; + *divr = n94x_common.syscon + syscon_i3c1fclksdiv; + break; + + case pctl_i3c0stc: + *selr = n94x_common.syscon + syscon_i3c0fclkstcsel; + *divr = n94x_common.syscon + syscon_i3c0fclkstcdiv; + break; + + case pctl_i3c1stc: + *selr = n94x_common.syscon + syscon_i3c1fclkstcsel; + *divr = n94x_common.syscon + syscon_i3c1fclkstcdiv; + break; + + case pctl_sai0: + *selr = n94x_common.syscon + syscon_sai0clksel; + *divr = n94x_common.syscon + syscon_sai0clkdiv; + break; + + case pctl_sai1: + *selr = n94x_common.syscon + syscon_sai1clksel; + *divr = n94x_common.syscon + syscon_sai1clkdiv; + break; + + /* enet TODO */ + + case pctl_micfil: + *selr = n94x_common.syscon + syscon_micfilfclksel; + *divr = n94x_common.syscon + syscon_micfilfclkdiv; + break; + + case pctl_tsi: + *selr = n94x_common.syscon + syscon_tsiclksel; + *divr = n94x_common.syscon + syscon_tsiclkdiv; + break; + + default: + break; + } + + return 0; +} + + +static void _mcxn94x_sysconSetDevClkState(int dev, int enable) +{ + int reg = dev >> 5; + int bit = dev & 0x1f; + + hal_cpuDataMemoryBarrier(); + if (enable != 0) { + /* Some fields are "reserved", let's try to control them anyway */ + *(n94x_common.syscon + syscon_ahbclkctrlset0 + reg) = 1u << bit; + } + else { + *(n94x_common.syscon + syscon_ahbclkctrlclr0 + reg) = 1u << bit; + } + hal_cpuDataMemoryBarrier(); +} + + +int _mcxn94x_sysconSetDevClk(int dev, unsigned int sel, unsigned int div, int enable) +{ + volatile u32 *selr = NULL, *divr = NULL; + + if (_mcxn94x_sysconGetRegs(dev, &selr, &divr) < 0) { + return -EINVAL; + } + + /* Disable the clock */ + _mcxn94x_sysconSetDevClkState(dev, 0); + + if (selr != NULL) { + *selr = sel & 0x7; + } + + if (divr != NULL) { + *divr = div & 0xff; + + /* Unhalt the divider */ + *divr &= ~(1 << 30); + } + + _mcxn94x_sysconSetDevClkState(dev, enable); + + return 0; +} + + +int _mcxn94x_sysconDevReset(int dev, int state) +{ + int reg = dev / 32; + int bit = dev & 0x1f; + + if ((dev < pctl_rom) || (dev > pctl_sema42)) { + return -EINVAL; + } + + if (state != 0) { + *(n94x_common.syscon + syscon_presetctrlset0 + reg) = 1 << bit; + } + else { + *(n94x_common.syscon + syscon_presetctrlcrl0 + reg) = 1 << bit; + } + hal_cpuDataMemoryBarrier(); + + return 0; +} + + +u64 _mcxn94x_sysconGray2Bin(u64 gray) +{ + u64 ret; + + *(n94x_common.syscon + syscon_graycodelsb) = gray & 0xffffffff; + *(n94x_common.syscon + syscon_graycodemsb) = gray >> 32; + hal_cpuDataMemoryBarrier(); + + ret = *(n94x_common.syscon + syscon_binarycodelsb); + ret |= ((u64)*(n94x_common.syscon + syscon_binarycodemsb)) << 32; + + return ret; +} + + +static void _mcxn94x_scgTrimUnlock(void) +{ + *(n94x_common.scg + scg_trimlock) = 0x5a5a0001; + hal_cpuDataMemoryBarrier(); +} + + +static void _mcxn94x_scgTrimLock(void) +{ + hal_cpuDataMemoryBarrier(); + *(n94x_common.scg + scg_trimlock) = 0x5a5a0000; +} + + +static void _mcxn94x_scgLdoConfig(u8 vout) +{ + u32 t; + + _mcxn94x_scgTrimUnlock(); + t = *(n94x_common.scg + scg_ldocsr) & ~0x1f; + *(n94x_common.scg + scg_ldocsr) = t | ((vout & 0x7) << 1) | 1; + hal_cpuDataMemoryBarrier(); + while ((*(n94x_common.scg + scg_ldocsr) & (1u << 31)) == 0) { + } + _mcxn94x_scgTrimLock(); +} + + +static void _mcxn94x_clockConfigOsc32khz(u8 extal, u8 cap, u8 gain) +{ + static const u32 mode = 0; /* Normal mode */ + u32 t; + + /* Setup oscillator startup time first (0.5 s) */ + t = *(n94x_common.vbat + vbat_osccfga) & ~(0x7 << 9); + *(n94x_common.vbat + vbat_osccfga) = t | (0x4 << 9); + hal_cpuDataMemoryBarrier(); + *(n94x_common.vbat + vbat_osccfgb) = ~(*(n94x_common.vbat + vbat_osccfga)); + hal_cpuDataMemoryBarrier(); + + /* Set oscillator to normal mode - skipping init mode seems to work just fine */ + *(n94x_common.vbat + vbat_oscctla) = (mode << 16) | ((extal & 0xf) << 12) | ((cap & 0xf) << 8) | (1 << 7) | ((gain & 0x3) << 2) | 1; + hal_cpuDataMemoryBarrier(); + *(n94x_common.vbat + vbat_oscctlb) = ~(*(n94x_common.vbat + vbat_oscctla)); + hal_cpuDataMemoryBarrier(); + while ((*(n94x_common.vbat + vbat_statusa) & (1 << 5)) == 0) { + } + + *(n94x_common.vbat + vbat_oscclke) |= 0xf; + hal_cpuDataMemoryBarrier(); + *(n94x_common.vbat + vbat_osclcka) |= 1; + *(n94x_common.vbat + vbat_osclckb) &= ~1; + hal_cpuDataMemoryBarrier(); +} + + +static void _mcxn94x_clockConfigExtClk(u32 freq) +{ + u8 range; + + if (freq < (20 * 1000 * 1000)) { + range = 0; + } + else if (freq < (30 * 1000 * 1000)) { + range = 1; + } + else if (freq < (50 * 1000 * 1000)) { + range = 2; + } + else { + range = 3; + } + + /* Clear errors if present */ + *(n94x_common.scg + scg_sosccsr) = (1 << 26); + + /* Set range and internal reference */ + *(n94x_common.scg + scg_sosccfg) = (range << 4) | (1 << 2); + + /* Unlock SOSCCSR */ + *(n94x_common.scg + scg_sosccsr) &= ~(1 << 23); + hal_cpuDataMemoryBarrier(); + + /* Enable clock and monitor */ + *(n94x_common.scg + scg_sosccsr) |= (1 << 17) | 1; + hal_cpuDataMemoryBarrier(); + + /* Wait for clock to stabilize */ + while ((*(n94x_common.scg + scg_sosccsr) & (1 << 24)) == 0) { + } +} + + +static void _mcxn94x_configBandGap(void) +{ + u32 t; + + /* Wait if busy */ + while ((*(n94x_common.spc + spc_sc) & 1) != 0) { + } + + /* Enable band-gap */ + t = *(n94x_common.spc + spc_activecfg) & ~(0x3 << 20); + *(n94x_common.spc + spc_activecfg) = t | (1 << 20); + hal_cpuDataMemoryBarrier(); +} + + +static void _mcxn94x_configDCDC(void) +{ + u32 t; + + /* For now only normal strength, OD voltage */ + + /* Wait if busy */ + while ((*(n94x_common.spc + spc_sc) & 1) != 0) { + } + + /* Select normal strength */ + t = *(n94x_common.spc + spc_activecfg) & ~(0x3 << 8); + *(n94x_common.spc + spc_activecfg) = t | (0x2 << 8); + hal_cpuDataMemoryBarrier(); + + /* Select OD voltage (1.2 V) */ + t = *(n94x_common.spc + spc_activecfg) & ~(0x3 << 10); + *(n94x_common.spc + spc_activecfg) = t | (0x3 << 10); + hal_cpuDataMemoryBarrier(); + + /* Wait if busy */ + while ((*(n94x_common.spc + spc_sc) & 1) != 0) { + } +} + + +static void _mcxn94x_configLDO(void) +{ + u32 t; + + /* For now only normal strength, OD voltage */ + + /* Wait if busy */ + while ((*(n94x_common.spc + spc_sc) & 1) != 0) { + } + + /* Select normal strength */ + *(n94x_common.spc + spc_activecfg) |= 1; + hal_cpuDataMemoryBarrier(); + + /* Select OD voltage (1.2 V) */ + t = *(n94x_common.spc + spc_activecfg) & ~(0x3 << 2); + *(n94x_common.spc + spc_activecfg) = t | (0x3 << 2); + hal_cpuDataMemoryBarrier(); +} + + +static void _mcxn94x_configFlashWS(u8 ws) +{ + u32 t = *(n94x_common.fmu + fmu_fctlr) & ~(0xf); + *(n94x_common.fmu + fmu_fctlr) = t | (ws & 0xf); + hal_cpuDataMemoryBarrier(); +} + + +static void _mcxn94x_configSramVoltage(u8 vsm) +{ + /* Set voltage */ + *(n94x_common.spc + spc_sramctl) = (vsm & 0x3); + hal_cpuDataMemoryBarrier(); + + /* Request change */ + *(n94x_common.spc + spc_sramctl) |= (1 << 30); + hal_cpuDataMemoryBarrier(); + + /* Wait for completion */ + while ((*(n94x_common.spc + spc_sramctl) & (1u << 31)) == 0) { + } + + *(n94x_common.spc + spc_sramctl) &= ~(1 << 30); + hal_cpuDataMemoryBarrier(); +} + + +static u8 _mcxn94x_clockGetSeli(u32 m) +{ + u32 a; + + if (m >= 8000) { + a = 1; + } + else if (m >= 122) { + a = 8000 / m; + } + else { + a = (2 * (m / 4)) + 3; + } + + return (a > 63) ? 63 : a; +} + + +static u8 _mcxn94x_clockGetSelp(u32 m) +{ + u32 a = (m >> 2) + 1; + return (a > 31) ? 31 : a; +} + + +static void _mcxn94x_clockConfigPLL0(u8 source, u8 mdiv, u8 pdiv, u8 ndiv) +{ + u8 seli = _mcxn94x_clockGetSeli(mdiv); + u8 selp = _mcxn94x_clockGetSelp(mdiv); + + /* Power off during config */ + *(n94x_common.scg + scg_apllcsr) &= ~((1 << 1) | 1); + hal_cpuDataMemoryBarrier(); + + /* Configure parameters */ + *(n94x_common.scg + scg_apllctrl) = ((source & 0x3) << 25) | ((selp & 0x1f) << 10) | ((seli & 0x3f) << 4); + *(n94x_common.scg + scg_apllndiv) = ndiv; + hal_cpuDataMemoryBarrier(); + *(n94x_common.scg + scg_apllndiv) = ndiv | (1u << 31); + *(n94x_common.scg + scg_apllpdiv) = pdiv; + hal_cpuDataMemoryBarrier(); + *(n94x_common.scg + scg_apllpdiv) = pdiv | (1u << 31); + *(n94x_common.scg + scg_apllmdiv) = mdiv; + hal_cpuDataMemoryBarrier(); + *(n94x_common.scg + scg_apllmdiv) = mdiv | (1u << 31); + hal_cpuDataMemoryBarrier(); + + /* Config lock time */ + _mcxn94x_scgTrimUnlock(); + *(n94x_common.scg + scg_aplllockcnfg) = ((SOSC_FREQ / ndiv) * 500) + 300; + _mcxn94x_scgTrimLock(); + + /* Enable PLL0 */ + *(n94x_common.scg + scg_apllcsr) |= (1 << 1) | 1; + hal_cpuDataMemoryBarrier(); + + /* Wait for lock */ + while ((*(n94x_common.scg + scg_apllcsr) & (1 << 24)) == 0) { + } + + /* Disable clock monitor */ + *(n94x_common.scg + scg_apllcsr) &= ~(1 << 16); +} + + +void _mcxn94x_disableGDET(void) +{ + u32 t; + + /* Disable aGDET trigger to the CHIP_RESET */ + t = *(n94x_common.itrc + itrc_outsel + (4 * 2)) & ~(0x3 << 18); + *(n94x_common.itrc + itrc_outsel + (4 * 2)) = t | (0x2 << 18); + t = *(n94x_common.itrc + itrc_outsel + (4 * 2) + 1) & ~(0x3 << 18); + *(n94x_common.itrc + itrc_outsel + (4 * 2) + 1) = t | (0x2 << 18); + hal_cpuDataMemoryBarrier(); + + /* Disable aGDET interrupt and reset */ + *(n94x_common.spc + spc_activecfg) |= (1 << 12); + *(n94x_common.spc + spc_glitchdetectsc) &= ~(1 << 16); + hal_cpuDataMemoryBarrier(); + *(n94x_common.spc + spc_glitchdetectsc) = 0x3c; + hal_cpuDataMemoryBarrier(); + *(n94x_common.spc + spc_glitchdetectsc) |= (1 << 16); + + /* Disable dGDET trigger to the CHIP_RESET */ + t = *(n94x_common.itrc + itrc_outsel + (4 * 2)) & ~0x3; + *(n94x_common.itrc + itrc_outsel + (4 * 2)) = t | 0x2; + t = *(n94x_common.itrc + itrc_outsel + (4 * 2) + 1) & ~0x3; + *(n94x_common.itrc + itrc_outsel + (4 * 2) + 1) = t | 0x2; + hal_cpuDataMemoryBarrier(); + + *(n94x_common.gdet0 + gdet_enable1) = 0; + *(n94x_common.gdet1 + gdet_enable1) = 0; + hal_cpuDataMemoryBarrier(); +} + + +void _mcxn94x_init(void) +{ + int i; + static u32 flexcommConf[] = { FLEXCOMM0_SEL, FLEXCOMM1_SEL, FLEXCOMM2_SEL, + FLEXCOMM3_SEL, FLEXCOMM4_SEL, FLEXCOMM5_SEL, FLEXCOMM6_SEL, FLEXCOMM7_SEL, + FLEXCOMM8_SEL, FLEXCOMM9_SEL }; + + n94x_common.syscon = (void *)0x40000000; + n94x_common.port[0] = (void *)0x40116000; + n94x_common.port[1] = (void *)0x40117000; + n94x_common.port[2] = (void *)0x40118000; + n94x_common.port[3] = (void *)0x40119000; + n94x_common.port[4] = (void *)0x4011a000; + n94x_common.port[5] = (void *)0x40042000; + n94x_common.inputmux = (void *)0x40006000; + n94x_common.flexcomm[0] = (void *)0x40092000; + n94x_common.flexcomm[1] = (void *)0x40093000; + n94x_common.flexcomm[2] = (void *)0x40094000; + n94x_common.flexcomm[3] = (void *)0x40095000; + n94x_common.flexcomm[4] = (void *)0x400b4000; + n94x_common.flexcomm[5] = (void *)0x400b5000; + n94x_common.flexcomm[6] = (void *)0x400b6000; + n94x_common.flexcomm[7] = (void *)0x400b7000; + n94x_common.flexcomm[8] = (void *)0x400b8000; + n94x_common.flexcomm[9] = (void *)0x400b9000; + n94x_common.vbat = (void *)0x40059000; + n94x_common.scg = (void *)0x40044000; + n94x_common.spc = (void *)0x40045000; + n94x_common.fmu = (void *)0x40043000; + n94x_common.gdet0 = (void *)0x40024000; + n94x_common.gdet1 = (void *)0x40025000; + n94x_common.itrc = (void *)0x40026000; + + _mcxn94x_disableGDET(); + + /* Configure FlexComms */ + for (i = 0; i < sizeof(flexcommConf) / sizeof(*flexcommConf); ++i) { + if (flexcommConf[i] == FLEXCOMM_NONE) { + continue; + } + + /* Enable FlexComms clock and select FRO_12M source */ + _mcxn94x_sysconSetDevClk(pctl_fc0 + i, 2, 0, 1); + + /* Select active interface */ + *(n94x_common.flexcomm[i] + flexcomm_pselid) = flexcommConf[i] & 0x7; + } + hal_cpuDataMemoryBarrier(); + + /* Disable RAM ECC to free up RAMH bank */ + *(n94x_common.syscon + syscon_eccenablectrl) = 0; + + /* Enable PORTn clocks */ + for (i = 0; i < sizeof(n94x_common.port) / sizeof(*n94x_common.port) - 1; ++i) { + /* PORT5 is reserved according to doc, let's enable it anyway */ + /* No sel/div for these, sel/div doesn't matter */ + _mcxn94x_sysconSetDevClk(pctl_port0 + i, 0, 0, 1); + } + + /* Enable the flash cache LPCAC */ + *(n94x_common.syscon + syscon_lpcacctrl) &= ~1; + + /* Enable LDO */ + _mcxn94x_scgLdoConfig(LDO_VOUT_1V1); + + /* Configure 32 KHz crystal pins */ + _mcxn94x_portPinConfig(pctl_pin_p5_0, 0, MCX_PIN_FAST | MCX_PIN_INPUT_BUFFER_ENABLE); + _mcxn94x_portPinConfig(pctl_pin_p5_1, 0, MCX_PIN_FAST | MCX_PIN_INPUT_BUFFER_ENABLE); + + /* Enable 32 KHz oscillator */ + /* TODO determine EXTAL_CAP_SEL, XTAL_CAP_SEL and COARSE_AMP_GAIN values */ + _mcxn94x_clockConfigOsc32khz(ROSC_EXTALCAP_PF / 2, ROSC_CAP_PF / 2, ROSC_AMP_GAIN); + + /* Configure 24 MHz oscillator pins */ + _mcxn94x_portPinConfig(pctl_pin_p1_30, 0, MCX_PIN_FAST | MCX_PIN_INPUT_BUFFER_ENABLE); + _mcxn94x_portPinConfig(pctl_pin_p1_31, 0, MCX_PIN_FAST | MCX_PIN_INPUT_BUFFER_ENABLE); + + /* Enable oscillator */ + _mcxn94x_clockConfigExtClk(SOSC_FREQ); + + /* Config power supply */ + _mcxn94x_configBandGap(); + _mcxn94x_configDCDC(); + _mcxn94x_configLDO(); + _mcxn94x_configSramVoltage(0x3); + + /* Config flash waitstates */ + _mcxn94x_configFlashWS(3); + + /* Enable PPL0 @150 MHz, SOSC source Fin = SOSC_FREQ / 4 */ + /* Fout = Fin * m / (2 * p * n) */ + _mcxn94x_clockConfigPLL0(0, 50, 100, 4); + + /* Select PLL0 as a main clock */ + *(n94x_common.scg + scg_rccr) = (*(n94x_common.scg + scg_rccr) & ~(0xf << 24)) | 5 << 24; + hal_cpuDataMemoryBarrier(); + + /* Wait for clock to change */ + while (((*(n94x_common.scg + scg_csr) >> 24) & 0xf) != 5) { + } + + /* Set AHB clock divider to clk / 1 */ + *(n94x_common.syscon + syscon_ahbclkdiv) = 0; + hal_cpuDataMemoryBarrier(); +} diff --git a/hal/armv8m/mcx/n94x/n94x.h b/hal/armv8m/mcx/n94x/n94x.h new file mode 100644 index 00000000..c37128a2 --- /dev/null +++ b/hal/armv8m/mcx/n94x/n94x.h @@ -0,0 +1,37 @@ +/* + * Phoenix-RTOS + * + * plo - operating system loader + * + * MCXN94x basic peripherals control functions + * + * Copyright 2024 Phoenix Systems + * Author: Aleksander Kaminski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _HAL_MCXN94X_H_ +#define _HAL_MCXN94X_H_ + +#include "hal/armv8m/mcx/types.h" +#include + + +extern int _mcxn94x_portPinConfig(int pin, int mux, int options); + + +extern int _mcxn94x_sysconSetDevClk(int dev, unsigned int sel, unsigned int div, int enable); + + +extern int _mcxn94x_sysconDevReset(int dev, int state); + + +extern u64 _mcxn94x_sysconGray2Bin(u64 gray); + + +extern void _mcxn94x_init(void); + +#endif diff --git a/hal/armv8m/mcx/n94x/peripherals.h b/hal/armv8m/mcx/n94x/peripherals.h new file mode 100644 index 00000000..85dfd97b --- /dev/null +++ b/hal/armv8m/mcx/n94x/peripherals.h @@ -0,0 +1,29 @@ +/* + * Phoenix-RTOS + * + * plo - operating system loader + * + * Peripherals definitions for armv8m33-mcxn94x + * + * Copyright 2024 Phoenix Systems + * Author: Aleksander Kaminski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _PERIPHERALS_H_ +#define _PERIPHERALS_H_ + +#include + +/* Periperals configuration */ + +#define SIZE_INTERRUPTS (171 + 16) + +#define FLASH_PROGRAM_1_ADDR 0x00000000u +#define FLASH_PROGRAM_2_ADDR 0x00100000u +#define FLASH_PROGRAM_BANK_SIZE (1024 * 1024) + +#endif diff --git a/hal/armv8m/mcx/n94x/timer.c b/hal/armv8m/mcx/n94x/timer.c new file mode 100644 index 00000000..69204f9a --- /dev/null +++ b/hal/armv8m/mcx/n94x/timer.c @@ -0,0 +1,90 @@ +/* + * Phoenix-RTOS + * + * Operating system loader + * + * Timer driver + * + * Copyright 2024 Phoenix Systems + * Author: Aleksander Kaminski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include +#include "n94x.h" + + +/* clang-format off */ +enum { ostimer_evtimerl = 0, ostimer_evtimerh, ostimer_capturel, ostimer_captureh, + ostimer_matchl, ostimer_matchh, ostimer_oseventctrl = 7 }; +/* clang-format on */ + + +static struct { + volatile u32 *base; + u32 high; + u64 timerLast; +} timer_common; + + +static u64 timer_gray2bin(u64 gray) +{ + return _mcxn94x_sysconGray2Bin(gray); +} + +static time_t hal_timerCyc2Us(time_t ticks) +{ + return (ticks * 1000 * 1000) / 32768; +} + + +static u64 hal_timerGetCyc(void) +{ + u32 high = *(timer_common.base + ostimer_evtimerh); + u32 low = *(timer_common.base + ostimer_evtimerl); + u64 timerval; + + if (high != *(timer_common.base + ostimer_evtimerh)) { + /* Rollover, read again */ + high = *(timer_common.base + ostimer_evtimerh); + low = *(timer_common.base + ostimer_evtimerl); + } + + timerval = timer_gray2bin(low | ((u64)high << 32)); + if (timerval < timer_common.timerLast) { + /* Once every ~4 years */ + timer_common.high += 1 << (42 - 32); + } + timer_common.timerLast = timerval; + + return timerval | timer_common.high; +} + + +time_t hal_timerGet(void) +{ + return hal_timerCyc2Us(hal_timerGetCyc()) / 1000; +} + + +void timer_done(void) +{ + /* Disable and reset the timer */ + _mcxn94x_sysconDevReset(pctl_ostimer, 1); +} + + +void timer_init(void) +{ + timer_common.base = (void *)0x40049000; + timer_common.timerLast = 0; + timer_common.high = 0; + + /* Configure OSTIMER clock */ + /* Use xtal32k clock source, enable the clock, deassert reset */ + _mcxn94x_sysconSetDevClk(pctl_ostimer, 1, 0, 1); + _mcxn94x_sysconDevReset(pctl_ostimer, 0); +} diff --git a/hal/armv8m/mcx/types.h b/hal/armv8m/mcx/types.h new file mode 100644 index 00000000..96ba148f --- /dev/null +++ b/hal/armv8m/mcx/types.h @@ -0,0 +1,46 @@ +/* + * Phoenix-RTOS + * + * Operating system loader + * + * Types + * + * Copyright 2021, 2022, 2024 Phoenix Systems + * Author: Hubert Buczynski, Gerard Swiderski, Aleksander Kaminski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _TYPES_H_ +#define _TYPES_H_ + + +#define NULL ((void *)0) + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +typedef signed char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef volatile unsigned char vu8; +typedef volatile unsigned short vu16; +typedef volatile unsigned int vu32; + +typedef vu8 *reg8; +typedef vu16 *reg16; +typedef vu32 *reg32; + +typedef unsigned int addr_t; +typedef unsigned int size_t; +typedef int ssize_t; +typedef unsigned long long time_t; + + +#endif diff --git a/hal/armv8m/nrf/91/config.h b/hal/armv8m/nrf/91/config.h index 52801d4a..3d1652a1 100644 --- a/hal/armv8m/nrf/91/config.h +++ b/hal/armv8m/nrf/91/config.h @@ -21,12 +21,12 @@ #include "nrf91.h" #include "peripherals.h" -#include "../types.h" +#include "hal/armv8m/nrf/types.h" #include #include -#include "../../cpu.h" +#include "hal/armv8m/cpu.h" #define PATH_KERNEL "phoenix-armv8m33-nrf9160.elf" diff --git a/ld/armv8m33-mcxn94x.ldt b/ld/armv8m33-mcxn94x.ldt new file mode 100644 index 00000000..9a429c9b --- /dev/null +++ b/ld/armv8m33-mcxn94x.ldt @@ -0,0 +1,56 @@ +/* + * Phoenix-RTOS + * + * Operating system loader + * + * Linker Template and Platform Config for MCXN94x + * + * Copyright 2021-2022, 2024 Phoenix Systems + * Author: Gerard Swiderski, Damian Loewnau, Aleksander Kaminski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#ifndef ARMV8M33_MCXN94X_LDT +#define ARMV8M33_MCXN94X_LDT + + +/* Platform specific definitions */ +#define SIZE_PAGE 0x200 +#define SIZE_STACK (8 * SIZE_PAGE) +#define SIZE_HEAP (8 * SIZE_PAGE) + +#define RAM_ADDR 0x20000000 +#define RAM_SIZE (384 * 1024) /* RAMH not available by default*/ + +/* Space reserved for kernel data */ +#define AREA_KERNEL 0x10000 + + +#if defined(__LINKER__) + +/* Memory map setup */ +MEMORY +{ + m_sram (rwx) : ORIGIN = RAM_ADDR + AREA_KERNEL, LENGTH = 384k - AREA_KERNEL + m_flash1 (rx) : ORIGIN = 0x00000000, LENGTH = 1024k + m_flash2 (rx) : ORIGIN = 0x00100000, LENGTH = 1024k +} + +/* FLASH image */ +REGION_ALIAS("PLO_IMAGE", m_flash1); +REGION_ALIAS("TCM_TEXT", m_flash1); +REGION_ALIAS("DATA", m_sram); +REGION_ALIAS("BSS", m_sram); +REGION_ALIAS("HEAP", m_sram); +REGION_ALIAS("STACK", m_sram); + +#include "common/plo-arm.lds" + +#endif /* end of __LINKER__ */ + + +#endif /* end of ARMV8M33_MCXN94X_LDT */