diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 1dbb40767ea..3b155b7adfb 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -49,6 +49,14 @@ config ARCH_CHIP_FVP_ARMV8R ---help--- ARM FVP virt platform (ARMv8r) +config ARCH_CHIP_IMX8 + bool "NXP iMX.8 Platform (ARMv8a)" + select ARCH_HAVE_ADDRENV + select ARCH_HAVE_IRQTRIGGER + select ARCH_NEED_ADDRENV_MAPPING + ---help--- + NXP iMX.8 (ARMv8a) applications processors + config ARCH_CHIP_ARM64_CUSTOM bool "Custom ARM64 chip" select ARCH_CHIP_CUSTOM @@ -184,6 +192,7 @@ config ARCH_CHIP default "a64" if ARCH_CHIP_A64 default "qemu" if ARCH_CHIP_QEMU default "fvp-v8r" if ARCH_CHIP_FVP_ARMV8R + default "imx8" if ARCH_CHIP_IMX8 config ARM_HAVE_NEON bool @@ -249,4 +258,9 @@ endif if ARCH_CHIP_FVP_ARMV8R source "arch/arm64/src/fvp-v8r/Kconfig" endif + +if ARCH_CHIP_IMX8 +source "arch/arm64/src/imx8/Kconfig" +endif + endif # ARCH_ARM64 diff --git a/arch/arm64/include/imx8/chip.h b/arch/arm64/include/imx8/chip.h new file mode 100644 index 00000000000..b952f1d88c4 --- /dev/null +++ b/arch/arm64/include/imx8/chip.h @@ -0,0 +1,78 @@ +/**************************************************************************** + * arch/arm64/include/imx8/chip.h + * + * 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_ARM64_INCLUDE_IMX8_CHIP_H__ +#define __ARCH_ARM64_INCLUDE_IMX8_CHIP_H__ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Number of bytes in @p x kibibytes/mebibytes/gibibytes */ + +#define KB(x) ((x) << 10) +#define MB(x) (KB(x) << 10) +#define GB(x) (MB(UINT64_C(x)) << 10) + +#if defined(CONFIG_ARCH_CHIP_IMX8_QUADMAX) + +#if CONFIG_ARM_GIC_VERSION == 3 || CONFIG_ARM_GIC_VERSION == 4 + +#define CONFIG_GICD_BASE 0x51a00000 +#define CONFIG_GICR_BASE 0x51b00000 +#define CONFIG_GICR_OFFSET 0x20000 + +#else + +#error CONFIG_ARM_GIC_VERSION should be 2, 3 or 4 + +#endif /* CONFIG_ARM_GIC_VERSION */ + +#define CONFIG_RAMBANK1_ADDR 0x80000000 +#define CONFIG_RAMBANK1_SIZE MB(128) + +#define CONFIG_DEVICEIO_BASEADDR 0x40000000 +#define CONFIG_DEVICEIO_SIZE MB(512) +#define CONFIG_LOAD_BASE 0x80280000 + +#define MPID_TO_CLUSTER_ID(mpid) ((mpid) & ~0xff) + +#endif + +/**************************************************************************** + * Assembly Macros + ****************************************************************************/ + +#ifdef __ASSEMBLY__ + +.macro get_cpu_id xreg0 + mrs \xreg0, mpidr_el1 + ubfx \xreg0, \xreg0, #0, #8 +.endm + +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_ARM64_INCLUDE_IMX8_CHIP_H */ diff --git a/arch/arm64/include/imx8/irq.h b/arch/arm64/include/imx8/irq.h new file mode 100644 index 00000000000..4bd44450635 --- /dev/null +++ b/arch/arm64/include/imx8/irq.h @@ -0,0 +1,34 @@ +/**************************************************************************** + * arch/arm64/include/imx8/irq.h + * + * 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_ARM64_INCLUDE_IMX8_IRQ_H__ +#define __ARCH_ARM64_INCLUDE_IMX8_IRQ_H__ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NR_IRQS 512 /* Total number of interrupts */ + +#endif /* __ARCH_ARM64_INCLUDE_IMX8_IRQ_H__ */ diff --git a/arch/arm64/src/imx8/Kconfig b/arch/arm64/src/imx8/Kconfig new file mode 100644 index 00000000000..3ebc6f4d554 --- /dev/null +++ b/arch/arm64/src/imx8/Kconfig @@ -0,0 +1,31 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +if ARCH_CHIP_IMX8 + +menu "iMX.8 Chip Selection" + +choice + prompt "iMX.8 Core Configuration" + default ARCH_CHIP_IMX8_QUADMAX + +config ARCH_CHIP_IMX8_QUADMAX + bool "iMX.8 QuadMax Application Processor" + select ARCH_HAVE_MULTICPU + select ARMV8A_HAVE_GICv3 + select ARCH_CORTEX_A53 + +endchoice # iMX.8 Chip Selection + +endmenu # "iMX.8 Chip Selection" + +menu "iMX.8 Peripheral Selection" +config IMX8_UART1 + bool "UART1" + default n + select UART1_SERIALDRIVER +endmenu # iMX Peripheral Selection + +endif # ARCH_CHIP_IMX8 diff --git a/arch/arm64/src/imx8/Make.defs b/arch/arm64/src/imx8/Make.defs new file mode 100644 index 00000000000..196f65b543e --- /dev/null +++ b/arch/arm64/src/imx8/Make.defs @@ -0,0 +1,32 @@ +############################################################################ +# arch/arm64/src/imx8/Make.defs +# +# 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 common/Make.defs + +# i.MX8-specific C source files + +CHIP_CSRCS = imx8_boot.c + +ifeq ($(CONFIG_ARCH_CHIP_IMX8_QUADMAX),y) + CHIP_CSRCS += imx8qm_serial.c + ifeq ($(CONFIG_ARCH_EARLY_PRINT),y) + CHIP_ASRCS = imx8qm_lowputc.S + endif +endif diff --git a/arch/arm64/src/imx8/chip.h b/arch/arm64/src/imx8/chip.h new file mode 100644 index 00000000000..d6a323010f8 --- /dev/null +++ b/arch/arm64/src/imx8/chip.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * arch/arm64/src/imx8/chip.h + * + * 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_ARM64_SRC_IMX8_CHIP_H +#define __ARCH_ARM64_SRC_IMX8_CHIP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifndef __ASSEMBLY__ +# include +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Macro Definitions + ****************************************************************************/ + +#endif /* __ARCH_ARM64_SRC_IMX8_CHIP_H */ diff --git a/arch/arm64/src/imx8/imx8_boot.c b/arch/arm64/src/imx8/imx8_boot.c new file mode 100644 index 00000000000..5d383430fcd --- /dev/null +++ b/arch/arm64/src/imx8/imx8_boot.c @@ -0,0 +1,115 @@ +/**************************************************************************** + * arch/arm64/src/imx8/imx8_boot.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 +#ifdef CONFIG_PAGING +# include +#endif + +#include +#include "arm64_arch.h" +#include "arm64_internal.h" +#include "arm64_mmu.h" +#include "imx8_boot.h" +#include "imx8_serial.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct arm_mmu_region g_mmu_regions[] = +{ + MMU_REGION_FLAT_ENTRY("DEVICE_REGION", + CONFIG_DEVICEIO_BASEADDR, MB(512), + MT_DEVICE_NGNRNE | MT_RW | MT_SECURE), + + MMU_REGION_FLAT_ENTRY("DRAM0_S0", + CONFIG_RAMBANK1_ADDR, MB(512), + MT_NORMAL | MT_RW | MT_SECURE), +}; + +const struct arm_mmu_config g_mmu_config = +{ + .num_regions = nitems(g_mmu_regions), + .mmu_regions = g_mmu_regions, +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm64_el_init + * + * Description: + * The function called from arm64_head.S at very early stage for these + * platform, it's use to: + * - Handling special hardware initialize routine which is need to + * run at high ELs + * - Initialize system software such as hypervisor or security firmware + * which is need to run at high ELs + * + ****************************************************************************/ + +void arm64_el_init(void) +{ + write_sysreg(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, cntfrq_el0); + + ARM64_ISB(); +} + +/**************************************************************************** + * Name: arm64_chip_boot + * + * Description: + * Complete boot operations started in arm64_head.S + * + ****************************************************************************/ + +void arm64_chip_boot(void) +{ + /* MAP IO and DRAM, enable MMU. */ + + arm64_mmu_init(true); + + /* Perform board-specific device initialization. This would include + * configuration of board specific resources such as GPIOs, LEDs, etc. + */ + + imx8_board_initialize(); + +#ifdef USE_EARLYSERIALINIT + /* Perform early serial initialization if we are going to use the serial + * driver. + */ + + arm64_earlyserialinit(); +#endif +} diff --git a/arch/arm64/src/imx8/imx8_boot.h b/arch/arm64/src/imx8/imx8_boot.h new file mode 100644 index 00000000000..24b44879db0 --- /dev/null +++ b/arch/arm64/src/imx8/imx8_boot.h @@ -0,0 +1,81 @@ +/**************************************************************************** + * arch/arm64/src/imx8/imx8_boot.h + * + * 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_ARM64_SRC_IMX8_IMX8_BOOT_H +#define __ARCH_ARM64_SRC_IMX8_IMX8_BOOT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 62500000 + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: imx8_board_initialize + * + * Description: + * All i.MX8 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 imx8_board_initialize(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM64_SRC_IMX8_IMX8_BOOT_H */ diff --git a/arch/arm64/src/imx8/imx8_serial.h b/arch/arm64/src/imx8/imx8_serial.h new file mode 100644 index 00000000000..16c2252a9b8 --- /dev/null +++ b/arch/arm64/src/imx8/imx8_serial.h @@ -0,0 +1,105 @@ +/**************************************************************************** + * arch/arm64/src/imx8/imx8_serial.h + * + * 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_ARM64_SRC_IMX8_IMX8_SERIAL_H +#define __ARCH_ARM64_SRC_IMX8_IMX8_SERIAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "arm64_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef CONFIG_ARCH_CHIP_IMX8_QUADMAX +#define SPI_OFFSET 32 +#define CONFIG_IMX8QM_UART1_BASE 0x5a060000 +#define CONFIG_IMX8QM_UART1_IRQ (SPI_OFFSET + 345) +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: imx_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. + * + ****************************************************************************/ + +#ifdef USE_EARLYSERIALINIT +void imx8_earlyserialinit(void); + +#endif + +/**************************************************************************** + * Name: uart_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. + * + ****************************************************************************/ + +#if defined(USE_EARLYSERIALINIT) && defined(IMX8_HAVE_UART) +void uart_earlyserialinit(void); + +#endif + +/**************************************************************************** + * Name: uart_serialinit + * + * Description: + * Register the UART serial console and serial ports. This assumes that + * uart_earlyserialinit was called previously. + * + ****************************************************************************/ + +#ifdef IMX8_HAVE_UART +void uart_serialinit(void); + +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_IMX6_IMX_SERIAL_H */ diff --git a/arch/arm64/src/imx8/imx8qm_lowputc.S b/arch/arm64/src/imx8/imx8qm_lowputc.S new file mode 100644 index 00000000000..899957cc4ff --- /dev/null +++ b/arch/arm64/src/imx8/imx8qm_lowputc.S @@ -0,0 +1,89 @@ +/**************************************************************************** + * arch/arm64/src/imx8/imx8_lowputs.S + * + * 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. + * + **************************************************************************** + * + * DESCRIPTION + * Wrapper for early printk + * + ***************************************************************************/ + +#include + +#include "arm64_macro.inc" + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + .file "imx8qm_lowputc.S" + +/**************************************************************************** + * Assembly Macros + ****************************************************************************/ + +/* 32-bit register definition for imx8qm uart*/ +#define UART1_BASE_ADDRESS 0x5a060000 + +#define UARTSTAT (0x14) +#define UARTDATA (0x1C) +#define UARTSTAT_TDRE (1 << 23) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* PL011 UART initialization */ + +GTEXT(arm64_earlyprintinit) +SECTION_FUNC(text, arm64_earlyprintinit) + /* Already initialized in bootloader */ + ret + +/* i.MX8QM wait LPUART to be ready to transmit + * rb: register which contains the UART base address + * rc: scratch register + */ +.macro early_uart_ready xb, c +1: + ldr w\c, [\xb, #UARTSTAT] /* <- Flag register */ + tst w\c, #UARTSTAT_TDRE /* Check FIFO EMPTY bit */ + beq 1b /* Wait for the UART to be ready */ +.endm + +/* i.MX8QM LPUART transmit character + * rb: register which contains the UART base address + * rt: register which contains the character to transmit */ +.macro early_uart_transmit xb, wt + str \wt, [\xb, #UARTDATA] /* -> Data Register */ +.endm + +/* + * Print a character on the UART - this function is called by C + * x0: character to print + */ +GTEXT(arm64_lowputc) +SECTION_FUNC(text, arm64_lowputc) + ldr x15, =UART1_BASE_ADDRESS + early_uart_ready x15, 1 + early_uart_transmit x15, w0 + ret diff --git a/arch/arm64/src/imx8/imx8qm_serial.c b/arch/arm64/src/imx8/imx8qm_serial.c new file mode 100644 index 00000000000..ce2dbf19a37 --- /dev/null +++ b/arch/arm64/src/imx8/imx8qm_serial.c @@ -0,0 +1,1096 @@ +/**************************************************************************** + * arch/arm64/src/imx8/imx8qm_serial.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 +#include + +#ifdef CONFIG_SERIAL_TERMIOS +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "chip.h" +#include "arm64_arch.h" +#include "arm64_internal.h" +#include "arm64_gic.h" + +#include "imx8_serial.h" +#include "imx8_boot.h" + +#ifdef USE_SERIALDRIVER + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Which UART with be tty0/console and which tty1-4? The console will + * always be ttyS0. If there is no console then will use the lowest + * numbered UART. + */ + +/* First pick the console and ttys0. This could be any of UART1-5 */ + +#if defined(CONFIG_UART1_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart1port /* UART1 is console */ +# define TTYS0_DEV g_uart1port /* UART1 is ttyS0 */ +# define UART1_ASSIGNED 1 +#endif + +/* 32-bit global registers only for i.MX7ulp/MX8x + * The driver only use the reset feature to reset HW. + */ +#define UART_GLOBAL 0x8 + +/* 32-bit register definition */ +#define UARTBAUD 0x00 +#define UARTSTAT 0x04 +#define UARTCTRL 0x08 +#define UARTDATA 0x0C +#define UARTMATCH 0x10 +#define UARTMODIR 0x14 +#define UARTFIFO 0x18 +#define UARTWATER 0x1c + +#define UARTBAUD_MAEN1 0x80000000 +#define UARTBAUD_MAEN2 0x40000000 +#define UARTBAUD_M10 0x20000000 +#define UARTBAUD_TDMAE 0x00800000 +#define UARTBAUD_RDMAE 0x00200000 +#define UARTBAUD_RIDMAE 0x00100000 +#define UARTBAUD_MATCFG 0x00400000 +#define UARTBAUD_BOTHEDGE 0x00020000 +#define UARTBAUD_RESYNCDIS 0x00010000 +#define UARTBAUD_LBKDIE 0x00008000 +#define UARTBAUD_RXEDGIE 0x00004000 +#define UARTBAUD_SBNS 0x00002000 +#define UARTBAUD_SBR 0x00000000 +#define UARTBAUD_SBR_MASK 0x1fff +#define UARTBAUD_OSR_MASK 0x1f +#define UARTBAUD_OSR_SHIFT 24 + +#define UARTSTAT_LBKDIF 0x80000000 +#define UARTSTAT_RXEDGIF 0x40000000 +#define UARTSTAT_MSBF 0x20000000 +#define UARTSTAT_RXINV 0x10000000 +#define UARTSTAT_RWUID 0x08000000 +#define UARTSTAT_BRK13 0x04000000 +#define UARTSTAT_LBKDE 0x02000000 +#define UARTSTAT_RAF 0x01000000 +#define UARTSTAT_TDRE 0x00800000 +#define UARTSTAT_TC 0x00400000 +#define UARTSTAT_RDRF 0x00200000 +#define UARTSTAT_IDLE 0x00100000 +#define UARTSTAT_OR 0x00080000 +#define UARTSTAT_NF 0x00040000 +#define UARTSTAT_FE 0x00020000 +#define UARTSTAT_PE 0x00010000 +#define UARTSTAT_MA1F 0x00008000 +#define UARTSTAT_M21F 0x00004000 + +#define UARTCTRL_R8T9 0x80000000 +#define UARTCTRL_R9T8 0x40000000 +#define UARTCTRL_TXDIR 0x20000000 +#define UARTCTRL_TXINV 0x10000000 +#define UARTCTRL_ORIE 0x08000000 +#define UARTCTRL_NEIE 0x04000000 +#define UARTCTRL_FEIE 0x02000000 +#define UARTCTRL_PEIE 0x01000000 +#define UARTCTRL_TIE 0x00800000 +#define UARTCTRL_TCIE 0x00400000 +#define UARTCTRL_RIE 0x00200000 +#define UARTCTRL_ILIE 0x00100000 +#define UARTCTRL_TE 0x00080000 +#define UARTCTRL_RE 0x00040000 +#define UARTCTRL_RWU 0x00020000 +#define UARTCTRL_SBK 0x00010000 +#define UARTCTRL_MA1IE 0x00008000 +#define UARTCTRL_MA2IE 0x00004000 +#define UARTCTRL_IDLECFG_OFF 0x8 +#define UARTCTRL_LOOPS 0x00000080 +#define UARTCTRL_DOZEEN 0x00000040 +#define UARTCTRL_RSRC 0x00000020 +#define UARTCTRL_M 0x00000010 +#define UARTCTRL_WAKE 0x00000008 +#define UARTCTRL_ILT 0x00000004 +#define UARTCTRL_PE 0x00000002 +#define UARTCTRL_PT 0x00000001 + +#define UARTDATA_NOISY 0x00008000 +#define UARTDATA_PARITYE 0x00004000 +#define UARTDATA_FRETSC 0x00002000 +#define UARTDATA_RXEMPT 0x00001000 +#define UARTDATA_IDLINE 0x00000800 +#define UARTDATA_MASK 0x3ff + +#define UARTMODIR_IREN 0x00020000 +#define UARTMODIR_RTSWATER_S 0x8 +#define UARTMODIR_TXCTSSRC 0x00000020 +#define UARTMODIR_TXCTSC 0x00000010 +#define UARTMODIR_RXRTSE 0x00000008 +#define UARTMODIR_TXRTSPOL 0x00000004 +#define UARTMODIR_TXRTSE 0x00000002 +#define UARTMODIR_TXCTSE 0x00000001 + +#define UARTFIFO_TXEMPT 0x00800000 +#define UARTFIFO_RXEMPT 0x00400000 +#define UARTFIFO_TXOF 0x00020000 +#define UARTFIFO_RXUF 0x00010000 +#define UARTFIFO_TXFLUSH 0x00008000 +#define UARTFIFO_RXFLUSH 0x00004000 +#define UARTFIFO_RXIDEN_MASK 0x7 +#define UARTFIFO_RXIDEN_OFF 10 +#define UARTFIFO_TXOFE 0x00000200 +#define UARTFIFO_RXUFE 0x00000100 +#define UARTFIFO_TXFE 0x00000080 +#define UARTFIFO_FIFOSIZE_MASK 0x7 +#define UARTFIFO_TXSIZE_OFF 4 +#define UARTFIFO_RXFE 0x00000008 +#define UARTFIFO_RXSIZE_OFF 0 +#define UARTFIFO_DEPTH(x) (0x1 << ((x) ? ((x) + 1) : 0)) + +#define UARTWATER_COUNT_MASK 0xff +#define UARTWATER_TXCNT_OFF 8 +#define UARTWATER_RXCNT_OFF 24 +#define UARTWATER_WATER_MASK 0xff +#define UARTWATER_TXWATER_OFF 0 +#define UARTWATER_RXWATER_OFF 16 + +#define UART_GLOBAL_RST 0x2 +#define RST_HW_MIN_MS 20 +#define RST_HW_MAX_MS 40 + +#define UARTFIFO_RXIDEN_RDRF 0x3 +#define UARTCTRL_IDLECFG 0x7 + +/* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */ +#define DMA_RX_TIMEOUT (10) +#define UART_AUTOSUSPEND_TIMEOUT 3000 + +/* IMX lpuart has four extra unused regs located at the beginning */ +#define IMX_REG_OFF 0x10 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct imx8_uart_port_s +{ + unsigned long iobase; + unsigned int baud; /* Configured baud */ + unsigned int irq_num; + unsigned int txfifo_size; + unsigned int rxfifo_size; + int is_console; +}; + +static inline uint32_t imx8_read(struct imx8_uart_port_s *port, + uint32_t off) +{ + return getreg32(port->iobase + off); +} + +static inline void imx8_write(struct imx8_uart_port_s *port, + uint32_t val, uint32_t off) +{ + putreg32(val, port->iobase + off); +} + +static int imx8_lpuart_stop_tx(struct imx8_uart_port_s *sport) +{ + unsigned long temp; + + temp = imx8_read(sport, UARTCTRL); + temp &= ~(UARTCTRL_TIE | UARTCTRL_TCIE); + imx8_write(sport, temp, UARTCTRL); + + return 0; +} + +static int imx8_lpuart_stop_rx(struct imx8_uart_port_s *sport) +{ + unsigned long temp; + + temp = imx8_read(sport, UARTCTRL); + imx8_write(sport, temp & ~UARTCTRL_RE, UARTCTRL); + + return 0; +} + +static int imx8_lpuart_start_tx(struct imx8_uart_port_s *sport) +{ + unsigned long temp; + + temp = imx8_read(sport, UARTCTRL); + imx8_write(sport, temp | UARTCTRL_TIE, UARTCTRL); + + return 0; +} + +static int imx8_lpuart_start_rx(struct imx8_uart_port_s *sport) +{ + unsigned long temp; + + temp = imx8_read(sport, UARTCTRL); + imx8_write(sport, temp | UARTCTRL_RE, UARTCTRL); + + return 0; +} + +/**************************************************************************** + * Name: imx8_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +static void imx8_rxint(struct uart_dev_s *dev, bool enable) +{ + struct imx8_uart_port_s *sport = (struct imx8_uart_port_s *)dev->priv; + + if (enable) + { + imx8_lpuart_start_rx(sport); + } + else + { + imx8_lpuart_stop_rx(sport); + } +} + +/**************************************************************************** + * Name: imx8_txint + * + * Description: + * Call to enable or disable TX interrupts + * + ****************************************************************************/ + +static void imx8_txint(struct uart_dev_s *dev, bool enable) +{ + struct imx8_uart_port_s *sport = (struct imx8_uart_port_s *)dev->priv; + + if (enable) + { + imx8_lpuart_start_tx(sport); + } + else + { + imx8_lpuart_stop_tx(sport); + } +} + +/**************************************************************************** + * Name: imx8_send + * + * Description: + * This method will send one byte on the UART + * + ****************************************************************************/ + +static void imx8_send(struct uart_dev_s *dev, int ch) +{ + struct imx8_uart_port_s *sport = (struct imx8_uart_port_s *)dev->priv; + + imx8_write(sport, ch, UARTDATA); +} + +/**************************************************************************** + * Name: imx8_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'. + * + ****************************************************************************/ + +static int imx8_receive(struct uart_dev_s *dev, unsigned int *status) +{ + struct imx8_uart_port_s *sport = (struct imx8_uart_port_s *)dev->priv; + unsigned int rx; + unsigned int sr; + + /* to clear the FE, OR, NF, FE, PE flags, + * read STAT then read DATA reg + */ + + sr = imx8_read(sport, UARTSTAT); + rx = imx8_read(sport, UARTDATA); + + *status = sr; + + return rx; +} + +/**************************************************************************** + * Name: imx8_rxavailable + * + * Description: + * Return true if the receive fifo is not empty + * + ****************************************************************************/ + +static bool imx8_rxavailable(struct uart_dev_s *dev) +{ + struct imx8_uart_port_s *sport = (struct imx8_uart_port_s *)dev->priv; + unsigned long sfifo = imx8_read(sport, UARTFIFO); + + if (sfifo & UARTFIFO_RXEMPT) + { + return false; + } + else + { + return true; + } +} + +/**************************************************************************** + * Name: imx8_txready + * + * Description: + * Return true if the tranmsit fifo is not full + * + ****************************************************************************/ + +static bool imx8_txready(struct uart_dev_s *dev) +{ + struct imx8_uart_port_s *sport = (struct imx8_uart_port_s *)dev->priv; + unsigned long txcnt; + + /* When TXFULL is set, there is no space in the Tx FIFO */ + + txcnt = imx8_read(sport, UARTWATER); + txcnt = txcnt >> UARTWATER_TXCNT_OFF; + txcnt &= UARTWATER_COUNT_MASK; + + if (txcnt < sport->txfifo_size) + { + return true; + } + else + { + return false; + } +} + +/**************************************************************************** + * Name: imx8_txempty + * + * Description: + * Return true if the transmit fifo is empty + * + ****************************************************************************/ + +static bool imx8_txempty(struct uart_dev_s *dev) +{ + struct imx8_uart_port_s *sport = (struct imx8_uart_port_s *)dev->priv; + unsigned long stat = imx8_read(sport, UARTSTAT); + unsigned long sfifo = imx8_read(sport, UARTFIFO); + + if (stat & UARTSTAT_TC && sfifo & UARTFIFO_TXEMPT) + { + return true; + } + else + { + return false; + } +} + +/**************************************************************************** + * Name: imx8_irq_handler (and front-ends) + * + * Description: + * This is the common UART interrupt handler. It should cal + * uart_transmitchars or uart_receivechar to perform the appropriate data + * transfers. + * + ****************************************************************************/ + +static int imx8_uart_irq_handler(int irq, void *context, void *arg) +{ + struct uart_dev_s *dev = (struct uart_dev_s *)arg; + struct imx8_uart_port_s *sport; + unsigned long sts; + unsigned long rxcount; + + DEBUGASSERT(dev != NULL && dev->priv != NULL); + sport = (struct imx8_uart_port_s *)dev->priv; + + sts = imx8_read(sport, UARTSTAT); + rxcount = imx8_read(sport, UARTWATER); + rxcount = rxcount >> UARTWATER_RXCNT_OFF; + + if (sts & UARTSTAT_RDRF || rxcount > 0) + { + uart_recvchars(dev); + } + + if (sts & UARTSTAT_TDRE) + { + uart_xmitchars(dev); + } + + imx8_write(sport, sts, UARTSTAT); + return OK; +} + +static int imx8_lpuart_hw_reset(struct imx8_uart_port_s *sport) +{ + unsigned long global_addr; + + if (sport->is_console) + { + return 0; + } + + global_addr = sport->iobase + UART_GLOBAL - IMX_REG_OFF; + putreg32(UART_GLOBAL_RST, global_addr); + + /* arch_timer_delay(RST_HW_MAX_MS); */ + + putreg32(0, global_addr); + + /* arch_timer_delay(RST_HW_MAX_MS); */ + + return 0; +} + +static int imx8_setup(struct uart_dev_s *dev) +{ + irqstate_t i_flags; + int ret; + struct imx8_uart_port_s *sport = (struct imx8_uart_port_s *)dev->priv; + + i_flags = up_irq_save(); + + sport->iobase += IMX_REG_OFF; + + ret = imx8_lpuart_hw_reset(sport); + if (ret < 0) + { + serr("failed to reset hw: %d\n", ret); + } + + up_irq_restore(i_flags); + + return ret; +} + +void board_timerhook(void) +{ +} + +/**************************************************************************** + * Name: imx8_shutdown + * + * Description: + * Disable the UART. This method is called when the serial + * port is closed + * + ****************************************************************************/ + +static void imx8_shutdown(struct uart_dev_s *dev) +{ + struct imx8_uart_port_s *sport = (struct imx8_uart_port_s *)dev->priv; + unsigned long temp; + irqstate_t i_flags; + + i_flags = up_irq_save(); + + /* clear statue */ + + temp = imx8_read(sport, UARTSTAT); + imx8_write(sport, temp, UARTSTAT); + + /* disable Rx/Tx DMA */ + + temp = imx8_read(sport, UARTBAUD); + temp &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE | UARTBAUD_RIDMAE); + imx8_write(sport, temp, UARTBAUD); + + /* disable Rx/Tx and interrupts */ + + temp = imx8_read(sport, UARTCTRL); + temp &= ~(UARTCTRL_TE | UARTCTRL_RE | UARTCTRL_TIE | + UARTCTRL_TCIE | UARTCTRL_RIE | UARTCTRL_ILIE | + UARTCTRL_LOOPS); + imx8_write(sport, temp, UARTCTRL); + imx8_write(sport, 0, UARTMODIR); + + up_irq_restore(i_flags); +} + +static void imx8_setup_watermark(struct imx8_uart_port_s *sport) +{ + unsigned long val; + unsigned long ctrl; + unsigned long ctrl_saved; + unsigned long rxiden_cnt; + + ctrl = imx8_read(sport, UARTCTRL); + ctrl_saved = ctrl; + ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_TE | + UARTCTRL_RIE | UARTCTRL_RE); + imx8_write(sport, ctrl, UARTCTRL); + + /* enable FIFO mode */ + + val = imx8_read(sport, UARTFIFO); + val |= UARTFIFO_TXFE | UARTFIFO_RXFE; + val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH; + val &= ~(UARTFIFO_RXIDEN_MASK << UARTFIFO_RXIDEN_OFF); + rxiden_cnt = 0; + val |= ((rxiden_cnt & UARTFIFO_RXIDEN_MASK) << UARTFIFO_RXIDEN_OFF); + + imx8_write(sport, val, UARTFIFO); + + /* set the watermark + * rx_watermark = 1; + */ + + val = (1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF); + imx8_write(sport, val, UARTWATER); + + /* Restore cr2 */ + + imx8_write(sport, ctrl_saved, UARTCTRL); +} + +static void imx8_setup_watermark_enable(struct imx8_uart_port_s *sport) +{ + uint32_t temp; + + imx8_setup_watermark(sport); + + temp = imx8_read(sport, UARTCTRL); + temp |= UARTCTRL_RE | UARTCTRL_TE; + temp |= UARTCTRL_IDLECFG << UARTCTRL_IDLECFG_OFF; + imx8_write(sport, temp, UARTCTRL); +} + +static void imx8_hw_disable(struct imx8_uart_port_s *sport) +{ + unsigned long temp; + + temp = imx8_read(sport, UARTCTRL); + temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE | + UARTCTRL_TIE | UARTCTRL_TE); + imx8_write(sport, temp, UARTCTRL); +} + +static void imx8_configure(struct imx8_uart_port_s *sport) +{ + unsigned long temp; + + temp = imx8_read(sport, UARTCTRL); + temp |= UARTCTRL_RIE | UARTCTRL_ILIE; + temp |= UARTCTRL_TIE; + imx8_write(sport, temp, UARTCTRL); +} + +static void imx8_hw_setup(struct imx8_uart_port_s *sport) +{ + irqstate_t i_flags; + + i_flags = up_irq_save(); + + imx8_hw_disable(sport); + + imx8_setup_watermark_enable(sport); + imx8_configure(sport); + up_enable_irq(sport->irq_num); + + up_irq_restore(i_flags); +} + +/**************************************************************************** + * Name: imx8_attach + * + * Description: + * Configure the UART to operation in interrupt driven mode. This method + * is called when the serial port 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 supports multiple levels of interrupt enabling). The RX + * and TX interrupts are not enabled until the txint() and rxint() methods + * are called. + * + ****************************************************************************/ + +static int imx8_attach(struct uart_dev_s *dev) +{ + struct imx8_uart_port_s *sport = (struct imx8_uart_port_s *)dev->priv; + int ret; + unsigned long temp; + + /* determine FIFO size */ + + temp = imx8_read(sport, UARTFIFO); + + sport->txfifo_size = UARTFIFO_DEPTH( + (temp >> UARTFIFO_TXSIZE_OFF) & UARTFIFO_FIFOSIZE_MASK); + sport->rxfifo_size = UARTFIFO_DEPTH( + (temp >> UARTFIFO_RXSIZE_OFF) & UARTFIFO_FIFOSIZE_MASK); + + ret = irq_attach(sport->irq_num, imx8_uart_irq_handler, dev); + + if (ret == OK) + { + imx8_hw_setup(sport); + } + else + { + sinfo("error ret=%d\n", ret); + } + + return ret; +} + +/**************************************************************************** + * Name: imx_detach + * + * Description: + * Detach UART interrupts. This method is called when the serial port is + * closed normally just before the shutdown method is called. The + * exception is the serial console which is never shutdown. + * + ****************************************************************************/ + +static void imx8_detach(struct uart_dev_s *dev) +{ + struct imx8_uart_port_s *sport = (struct imx8_uart_port_s *)dev->priv; + + up_disable_irq(sport->irq_num); + irq_detach(sport->irq_num); +} + +/**************************************************************************** + * Name: imx8_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * for current imx8qm configure, + * + ****************************************************************************/ + +static int imx8_ioctl(struct file *filep, int cmd, unsigned long arg) +{ +#if defined(CONFIG_SERIAL_TIOCSERGSTRUCT) || defined(CONFIG_SERIAL_TERMIOS) + 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 imx_uart_s *user = (struct imx_uart_s *)arg; + if (!user) + { + ret = -EINVAL; + } + else + { + memcpy(user, dev, sizeof(struct imx_uart_s)); + } + } + break; +#endif + +#ifdef CONFIG_SERIAL_TERMIOS + case TCGETS: + { + struct termios *termiosp = (struct termios *)arg; + struct imx_uart_s *priv = (struct imx_uart_s *)dev->priv; + + 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 imx_uart_s *priv = (struct imx_uart_s *)dev->priv; + 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->cts_gpio == 0)) +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + || ((termiosp->c_cflag & CRTS_IFLOW) && (priv->rts_gpio == 0)) +#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; +#ifdef CONFIG_SERIAL_OFLOWCONTROL + priv->oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0; +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + priv->iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0; +#endif + + /* effect the changes immediately - note that we do not + * implement TCSADRAIN / TCSAFLUSH + */ + + flags = spin_lock_irqsave(NULL); + imx8_disableuartint(priv, &ie); + ret = imx8_setup(dev); + + /* Restore the interrupt state */ + + imx_restoreuartint(priv, ie); + priv->ie = ie; + spin_unlock_irqrestore(NULL, flags); + } + } + break; +#endif /* CONFIG_SERIAL_TERMIOS */ + + case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ + case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ + default: + { + ret = -ENOTTY; + break; + } + } + + return ret; +} + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Serial driver UART operations */ + +static const struct uart_ops_s g_uart_ops = +{ + .setup = imx8_setup, + .shutdown = imx8_shutdown, + .attach = imx8_attach, + .detach = imx8_detach, + .ioctl = imx8_ioctl, + .receive = imx8_receive, + .rxint = imx8_rxint, + .rxavailable = imx8_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = NULL, +#endif + .send = imx8_send, + .txint = imx8_txint, + .txready = imx8_txready, + .txempty = imx8_txempty, +}; + +/* I/O buffers */ + +#ifdef CONFIG_IMX8_UART1 +static char g_uart1rxbuffer[CONFIG_UART1_RXBUFSIZE]; +static char g_uart1txbuffer[CONFIG_UART1_TXBUFSIZE]; + +/* This describes the state of the IMX uart1 port. */ + +static struct imx8_uart_port_s g_uart1priv = +{ + .iobase = CONFIG_IMX8QM_UART1_BASE, + .baud = CONFIG_UART1_BAUD, + .irq_num = CONFIG_IMX8QM_UART1_IRQ, + .is_console = 1, +}; + +static struct uart_dev_s g_uart1port = +{ + .recv = + { + .size = CONFIG_UART1_RXBUFSIZE, + .buffer = g_uart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART1_TXBUFSIZE, + .buffer = g_uart1txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart1priv, +}; + +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm64_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 arm64_serialinit. + * + ****************************************************************************/ + +void arm64_earlyserialinit(void) +{ + /* NOTE: This function assumes that low level hardware configuration + * -- including all clocking and pin configuration -- was performed by the + * function imx8_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.isconsole = true; + imx8_setup(&CONSOLE_DEV); +#endif +} + +/* Used to assure mutually exclusive access up_putc() */ + +/* static sem_t g_putc_lock = SEM_INITIALIZER(1); */ + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug + * writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ + struct uart_dev_s *dev = &CONSOLE_DEV; + + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + imx8_send(dev, '\r'); + } + + imx8_send(dev, (uint8_t)ch); + return ch; +} + +/**************************************************************************** + * Name: arm64_serialinit + * + * Description: + * Register serial console and serial ports. This assumes + * that imx_earlyserialinit was called previously. + * + ****************************************************************************/ + +void arm64_serialinit(void) +{ + int ret; + + ret = uart_register("/dev/console", &CONSOLE_DEV); + if (ret < 0) + { + sinfo("error at register dev/console, ret =%d\n", ret); + } + + ret = uart_register("/dev/ttyS0", &TTYS0_DEV); + + if (ret < 0) + { + sinfo("error at register dev/ttyS0, ret =%d\n", ret); + } +} + +#endif /* USE_SERIALDRIVER */