diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 4edb0bf0673..4e5a2a4bc90 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -100,6 +100,17 @@ config ARCH_CHIP_IMX9 ---help--- NXP i.MX9 (ARMv8.2a) applications processors +config ARCH_CHIP_ZYNQ_MPSOC + bool "XilinX Zynq UltraScale+ MPSoC" + select ARCH_CORTEX_A53 + select ARCH_HAVE_ADDRENV + select ARCH_HAVE_RESET + select ARCH_HAVE_IRQTRIGGER + select ARCH_NEED_ADDRENV_MAPPING + select ARM64_HAVE_PSCI + ---help--- + XilinX ZYNQ MPSOC + config ARCH_CHIP_ARM64_CUSTOM bool "Custom ARM64 chip" select ARCH_CHIP_CUSTOM @@ -245,6 +256,7 @@ config ARCH_CHIP string default "a64" if ARCH_CHIP_A64 default "rk3399" if ARCH_CHIP_RK3399 + default "zynq-mpsoc" if ARCH_CHIP_ZYNQ_MPSOC default "qemu" if ARCH_CHIP_QEMU default "goldfish" if ARCH_CHIP_GOLDFISH default "fvp-v8r" if ARCH_CHIP_FVP_ARMV8R @@ -362,4 +374,8 @@ if ARCH_CHIP_GOLDFISH source "arch/arm64/src/goldfish/Kconfig" endif +if ARCH_CHIP_ZYNQ_MPSOC +source "arch/arm64/src/zynq-mpsoc/Kconfig" +endif + endif # ARCH_ARM64 diff --git a/arch/arm64/include/zynq-mpsoc/chip.h b/arch/arm64/include/zynq-mpsoc/chip.h new file mode 100644 index 00000000000..0d74c8e23e7 --- /dev/null +++ b/arch/arm64/include/zynq-mpsoc/chip.h @@ -0,0 +1,71 @@ +/**************************************************************************** + * arch/arm64/include/zynq-mpsoc/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_ZYNQ_MPSOC_CHIP_H +#define __ARCH_ARM64_INCLUDE_ZYNQ_MPSOC_CHIP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Number of bytes in x kibibytes/mebibytes/gibibytes */ + +#define KB(x) ((x) << 10) +#define MB(x) (KB(x) << 10) +#define GB(x) (MB(UINT64_C(x)) << 10) + +/* XilinX ZYNQ_MPSOC Generic Interrupt Controller v2: Distributor & Redist */ + +#define CONFIG_GICD_BASE 0xf9010000 +#define CONFIG_GICR_BASE 0xf9020000 +#define CONFIG_GICR_OFFSET 0x20000 + +/* XilinX ZYNQ_MPSOC Memory Map: RAM and Device I/O */ + +#define CONFIG_RAMBANK1_ADDR 0x00000000 +#define CONFIG_RAMBANK1_SIZE MB(2047) +#define CONFIG_DEVICEIO_BASEADDR 0xE0000000 +#define CONFIG_DEVICEIO_SIZE MB(512) + +/* U-Boot loads NuttX at this address (kernel_addr_r) */ + +#define CONFIG_LOAD_BASE 0x02080000 + +#define MPID_TO_CLUSTER_ID(mpid) ((mpid) & ~0xff) +/**************************************************************************** + * 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_ZYNQ_MPSOC_CHIP_H */ diff --git a/arch/arm64/include/zynq-mpsoc/irq.h b/arch/arm64/include/zynq-mpsoc/irq.h new file mode 100644 index 00000000000..2e3e0dd94f3 --- /dev/null +++ b/arch/arm64/include/zynq-mpsoc/irq.h @@ -0,0 +1,110 @@ +/**************************************************************************** + * arch/arm64/include/zynq-mpsoc/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_ZYNQ_MPSOC_IRQ_H +#define __ARCH_ARM64_INCLUDE_ZYNQ_MPSOC_IRQ_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Rockchip ZYNQ_MPSOC Interrupts */ + +#define NR_IRQS 166 /* Total number of interrupts */ + +#define ZYNQ_MPSOC_IRQ_RPU0_PERF_MON 40 /* RPU0 performance monitor IRQ */ +#define ZYNQ_MPSOC_IRQ_RPU1_PERF_MON 41 /* RPU1 performance monitorIRQ */ +#define ZYNQ_MPSOC_IRQ_OCM_ECC_ERROR 42 /* OCM CE or UE ECC error IRQ */ +#define ZYNQ_MPSOC_IRQ_LPD_APB_ERROR 43 /* APB slave port error IRQ */ +#define ZYNQ_MPSOC_IRQ_RPU0_ECC_ERROR 44 /* RPU0 ECC error IRQ */ +#define ZYNQ_MPSOC_IRQ_RPU1_ECC_ERROR 45 /* RPU0 ECC error IRQ */ +#define ZYNQ_MPSOC_IRQ_NAND 46 /* NAND controller IRQ */ +#define ZYNQ_MPSOC_IRQ_QSPI 47 /* QSPI controller IRQ */ +#define ZYNQ_MPSOC_IRQ_GPIO 48 /* GPIO controller IRQ */ +#define ZYNQ_MPSOC_IRQ_I2C0 49 /* I2C0 controller IRQ */ +#define ZYNQ_MPSOC_IRQ_I2C1 50 /* I2C1 controller IRQ */ +#define ZYNQ_MPSOC_IRQ_SPI0 51 /* SPI0 controller IRQ */ +#define ZYNQ_MPSOC_IRQ_SPI1 52 /* SPI1 controller IRQ */ +#define ZYNQ_MPSOC_IRQ_UART0 53 /* UART0 controller IRQ */ +#define ZYNQ_MPSOC_IRQ_UART1 54 /* UART1 controller IRQ */ +#define ZYNQ_MPSOC_IRQ_CAN0 55 /* CAN0 controller IRQ */ +#define ZYNQ_MPSOC_IRQ_CAN1 56 /* CAN1 controller IRQ */ +#define ZYNQ_MPSOC_IRQ_LPD_APM 57 /* LPD and OCM APM IRQ */ +#define ZYNQ_MPSOC_IRQ_RTC_ALARM 58 /* RTC alarm IRQ */ +#define ZYNQ_MPSOC_IRQ_RTC_SECONDS 59 /* RTC sceond IRQ */ +#define ZYNQ_MPSOC_IRQ_CLKMON 60 /* LPD clock test IRQ */ +#define ZYNQ_MPSOC_IRQ_IPI_CH7 61 /* IPI channel 7 IRQ */ +#define ZYNQ_MPSOC_IRQ_IPI_CH8 62 /* IPI channel 8 IRQ */ +#define ZYNQ_MPSOC_IRQ_IPI_CH9 63 /* IPI channel 9 IRQ */ +#define ZYNQ_MPSOC_IRQ_IPI_CH10 64 /* IPI channel 10 IRQ */ +#define ZYNQ_MPSOC_IRQ_IPI_CH2 65 /* IPI channel 2 IRQ */ +#define ZYNQ_MPSOC_IRQ_IPI_CH1 66 /* IPI channel 1 IRQ */ +#define ZYNQ_MPSOC_IRQ_IPI_CH0 67 /* IPI channel 0 IRQ */ +#define ZYNQ_MPSOC_IRQ_TTC0 68 /* TTC0 timer IRQ */ +#define ZYNQ_MPSOC_IRQ_TTC1 71 /* TTC1 timer IRQ */ +#define ZYNQ_MPSOC_IRQ_TTC2 74 /* TTC2 timer IRQ */ +#define ZYNQ_MPSOC_IRQ_TTC3 77 /* TTC3 timer IRQ */ +#define ZYNQ_MPSOC_IRQ_SDIO0 80 /* SDIO0 controller IRQ */ +#define ZYNQ_MPSOC_IRQ_SDIO1 81 /* SDIO1 controller IRQ */ +#define ZYNQ_MPSOC_IRQ_SDIO0_WAKEUP 82 /* SDIO0 controller wakeup IRQ */ +#define ZYNQ_MPSOC_IRQ_SDIO1_WAKEUP 83 /* SDIO1 controller wakeup IRQ */ +#define ZYNQ_MPSOC_IRQ_LPD_SWDT 84 /* LPD watch dog IRQ */ +#define ZYNQ_MPSOC_IRQ_CSU_SWDT 85 /* CSU watch dog IRQ */ +#define ZYNQ_MPSOC_IRQ_LPD_ATB 86 /* LPD ATB IRQ */ +#define ZYNQ_MPSOC_IRQ_AIB 87 /* AIB IRQ */ +#define ZYNQ_MPSOC_IRQ_SYSMON 88 /* interrupt monitor IRQ */ +#define ZYNQ_MPSOC_IRQ_GEM0 89 /* GEM0 controller IRQ */ +#define ZYNQ_MPSOC_IRQ_GEM0_WAKEUP 90 /* GEM0 controller wakeup IRQ */ +#define ZYNQ_MPSOC_IRQ_GEM1 91 /* GEM1 controller IRQ */ +#define ZYNQ_MPSOC_IRQ_GEM1_WAKEUP 92 /* GEM1 controller wakeup IRQ */ +#define ZYNQ_MPSOC_IRQ_GEM2 93 /* GEM2 controller IRQ */ +#define ZYNQ_MPSOC_IRQ_GEM2_WAKEUP 94 /* GEM2 controller wakeup IRQ */ +#define ZYNQ_MPSOC_IRQ_GEM3 95 /* GEM3 controller IRQ */ +#define ZYNQ_MPSOC_IRQ_GEM3_WAKEUP 96 /* GEM3 controller wakeup IRQ */ +#define ZYNQ_MPSOC_IRQ_USB0_ENDPOINT 97 /* USB0 controller IRQ */ +#define ZYNQ_MPSOC_IRQ_USB0_OTG 101 /* USB0 OTG controller IRQ */ +#define ZYNQ_MPSOC_IRQ_USB1_ENDPOINT 102 /* USB1 controller IRQ */ +#define ZYNQ_MPSOC_IRQ_USB1_OTG 106 /* USB1 OTG controller IRQ */ +#define ZYNQ_MPSOC_IRQ_USB0_WAKEUP 107 /* USB0 controller wakeup IRQ */ +#define ZYNQ_MPSOC_IRQ_USB1_WAKEUP 108 /* USB1 controller wakeup IRQ */ +#define ZYNQ_MPSOC_IRQ_LPD_DMA 109 /* LPD DMA controller IRQ */ +#define ZYNQ_MPSOC_IRQ_CSU 117 /* config and security IRQ */ +#define ZYNQ_MPSOC_IRQ_CSU_DMA 118 /* CSU DMA controller IRQ */ +#define ZYNQ_MPSOC_IRQ_EFUSE 119 /* eFuse controller IRQ */ + +#define ZYNQ_MPSOC_IRQ_PCIE_MSI0 146 /* PCIe MSI interrupt 0-31 */ +#define ZYNQ_MPSOC_IRQ_PCIE_MSI1 147 /* PCIe MSI interrupt 32-63 */ +#define ZYNQ_MPSOC_IRQ_PCIE_INTX 148 /* PCIe INTxIRQ */ +#define ZYNQ_MPSOC_IRQ_PCIE_DMA 149 /* PCIe DMA controller IRQ */ +#define ZYNQ_MPSOC_IRQ_PCIE_MSC 150 /* PCIe MSC controller IRQ */ +#define ZYNQ_MPSOC_IRQ_DISPLAY 151 /* display controller IRQ */ +#define ZYNQ_MPSOC_IRQ_FPD_APB 152 +#define ZYNQ_MPSOC_IRQ_FPD_ATB 153 +#define ZYNQ_MPSOC_IRQ_DPDMA 154 /* display DMA controller IRQ */ +#define ZYNQ_MPSOC_IRQ_FPD_APM 155 +#define ZYNQ_MPSOC_IRQ_FPD_DMA 156 +#define ZYNQ_MPSOC_IRQ_GPU 164 /* GPU controller IRQ */ +#define ZYNQ_MPSOC_IRQ_SATA 165 /* SATA controller IRQ */ + +#endif /* __ARCH_ARM64_INCLUDE_ZYNQ_MPSOC_IRQ_H */ diff --git a/arch/arm64/src/zynq-mpsoc/Kconfig b/arch/arm64/src/zynq-mpsoc/Kconfig new file mode 100644 index 00000000000..56836b87098 --- /dev/null +++ b/arch/arm64/src/zynq-mpsoc/Kconfig @@ -0,0 +1,46 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +if ARCH_CHIP_ZYNQ_MPSOC + +config XPAR_CPU_CORTEXA53_0_CPU_CLK_FREQ_HZ + int "Zynq Mpsoc cpu clock" + default 1199988037 + ---help--- + Canonical definitions for cpu PSU_CORTEXA53_0. + +config XPAR_CPU_CORTEXA53_0_TIMESTAMP_CLK_FREQ + int "Zynq Mpsoc peripheral clock" + default 99999001 + ---help--- + Canonical definitions for peripheral PSU_CORTEXA53_0. + +config XPAR_PSU_UART_0_UART_CLK_FREQ_HZ + int "Zynq Mpsoc uart0 clock" + default 99999001 + ---help--- + Clock definitions for uart0. + +menu "XILINX ZYNQ_MPSOC Peripheral Selection" + +config ZYNQ_MPSOC_UART0 + bool "UART 0" + default y + select UART0_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS + ---help--- + Select to enable support for UART0. + +config ZYNQ_MPSOC_UART1 + bool "UART 1" + default n + select UART1_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS + ---help--- + Select to enable support for UART1. + +endmenu # XILINX ZYNQ_MPSOC Peripheral Selection + +endif # ARCH_CHIP_ZYNQ_MPSOC diff --git a/arch/arm64/src/zynq-mpsoc/Make.defs b/arch/arm64/src/zynq-mpsoc/Make.defs new file mode 100644 index 00000000000..e600d84807e --- /dev/null +++ b/arch/arm64/src/zynq-mpsoc/Make.defs @@ -0,0 +1,28 @@ +############################################################################ +# arch/arm64/src/zynq-mpsoc/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 + +# Rockchip zynq mpsoc specific C source files +CHIP_CSRCS = zynq_boot.c zynq_serial.c + +ifeq ($(CONFIG_ARCH_EARLY_PRINT),y) +CHIP_ASRCS = zynq_lowputc.S +endif diff --git a/arch/arm64/src/zynq-mpsoc/chip.h b/arch/arm64/src/zynq-mpsoc/chip.h new file mode 100644 index 00000000000..2b77c00656e --- /dev/null +++ b/arch/arm64/src/zynq-mpsoc/chip.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * arch/arm64/src/zynq-mpsoc/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_ZYNQ_MPSOC_CHIP_H +#define __ARCH_ARM64_SRC_ZYNQ_MPSOC_CHIP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifndef __ASSEMBLY__ +# include +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Macro Definitions + ****************************************************************************/ + +#endif /* __ARCH_ARM64_SRC_ZYNQ_MPSOC_CHIP_H */ diff --git a/arch/arm64/src/zynq-mpsoc/hardware/zynq_memorymap.h b/arch/arm64/src/zynq-mpsoc/hardware/zynq_memorymap.h new file mode 100644 index 00000000000..566bcbd8a0b --- /dev/null +++ b/arch/arm64/src/zynq-mpsoc/hardware/zynq_memorymap.h @@ -0,0 +1,80 @@ +/**************************************************************************** + * arch/arm64/src/zynq-mpsoc/hardware/zynq_memorymap.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_ZYNQ_ZYNQ_MPSOC_HARDWARE_ZYNQ_MEMORYMAP_H +#define __ARCH_ARM64_SRC_ZYNQ_ZYNQ_MPSOC_HARDWARE_ZYNQ_MEMORYMAP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Peripheral Base Addresses */ + +#define ZYNQ_MPSOC_UART0_ADDR 0xFF000000 /* UART0 reg base address */ +#define ZYNQ_MPSOC_UART1_ADDR 0xFF010000 /* UART1 reg base address */ +#define ZYNQ_MPSOC_I2C0_ADDR 0xFF020000 /* I2C0 reg base address */ +#define ZYNQ_MPSOC_I2C1_ADDR 0xFF030000 /* I2C1 reg base address */ +#define ZYNQ_MPSOC_SPI0_ADDR 0xFF040000 /* SPI0 reg base address */ +#define ZYNQ_MPSOC_SPI1_ADDR 0xFF050000 /* SPI1 reg base address */ +#define ZYNQ_MPSOC_CAN0_ADDR 0xFF060000 /* CAN0 reg base address */ +#define ZYNQ_MPSOC_CAN1_ADDR 0xFF070000 /* CAN1 reg base address */ +#define ZYNQ_MPSOC_GPIO_ADDR 0xFF0A0000 /* GPIO reg base address */ +#define ZYNQ_MPSOC_GEM0_ADDR 0xFF0B0000 /* GEM0 reg base address */ +#define ZYNQ_MPSOC_GEM1_ADDR 0xFF0C0000 /* GEM1 reg base address */ +#define ZYNQ_MPSOC_GEM2_ADDR 0xFF0D0000 /* GEM2 reg base address */ +#define ZYNQ_MPSOC_GEM3_ADDR 0xFF0E0000 /* GEM3 reg base address */ +#define ZYNQ_MPSOC_MDIO_ADDR(ch) 0xFF0B0000 /* GEM3 reg base address */ +#define ZYNQ_MPSOC_QSPI_ADDR 0xFF0F0000 /* QSPI reg base address */ +#define ZYNQ_MPSOC_TTC0_ADDR 0xFF110000 /* NAND reg base address */ +#define ZYNQ_MPSOC_TTC1_ADDR 0xFF120000 /* TTC0 reg base address */ +#define ZYNQ_MPSOC_TTC2_ADDR 0xFF130000 /* TTC1 reg base address */ +#define ZYNQ_MPSOC_TTC3_ADDR 0xFF140000 /* TTC2 reg base address */ +#define ZYNQ_MPSOC_SD0_ADDR 0xFF160000 /* SD0 reg base address */ +#define ZYNQ_MPSOC_SD1_ADDR 0xFF170000 /* SD1 reg base address */ +#define ZYNQ_MPSOC_IOU_SLCR_ADDR 0xFF180000 /* IOU reg base address */ +#define ZYNQ_MPSOC_IPIBUF_ADDR 0xFF990000 /* IPI buffer base address */ +#define ZYNQ_MPSOC_USB0_ADDR 0xFF9D0000 /* USB0 reg base address */ +#define ZYNQ_MPSOC_USB1_ADDR 0xFF9E0000 /* USB1 reg base address */ +#define ZYNQ_MPSOC_AMS_ADDR 0xFFA50000 /* AMS reg base address */ +#define ZYNQ_MPSOC_PSSYSMON_ADDR 0xFFA50800 /* PS sys monitor reg base */ +#define ZYNQ_MPSOC_PLSYSMON_ADDR 0xFFA50C00 /* PL sys monitor reg base */ +#define ZYNQ_MPSOC_CSU_SWDT_ADDR 0xFFCB0000 /* CSU wdg mon reg base */ +#define ZYNQ_MPSOC_CRF_APB_CLKC_ADDR 0xFD1A0000 +#define ZYNQ_MPSOC_CRL_APB_CLKC_ADDR 0xFF5E0000 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +#endif /* __ARCH_ARM64_SRC_ZYNQ_ZYNQ_MPSOC_HARDWARE_ZYNQ_MEMORYMAP_H */ diff --git a/arch/arm64/src/zynq-mpsoc/zynq_boot.c b/arch/arm64/src/zynq-mpsoc/zynq_boot.c new file mode 100644 index 00000000000..5a708670749 --- /dev/null +++ b/arch/arm64/src/zynq-mpsoc/zynq_boot.c @@ -0,0 +1,209 @@ +/**************************************************************************** + * arch/arm64/src/zynq-mpsoc/zynq_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_LEGACY_PAGING +# include +#endif + +#include + +#ifdef CONFIG_SMP +#include "arm64_smp.h" +#endif + +#include "arm64_arch.h" +#include "arm64_internal.h" +#include "arm64_mmu.h" +#include "zynq_boot.h" +#include "zynq_serial.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct arm_mmu_region g_mmu_regions[] = +{ + MMU_REGION_FLAT_ENTRY("DEVICE_REGION", + CONFIG_DEVICEIO_BASEADDR, CONFIG_DEVICEIO_SIZE, + MT_DEVICE_NGNRNE | MT_RW | MT_SECURE), + + MMU_REGION_FLAT_ENTRY("DRAM0_S0", + CONFIG_RAMBANK1_ADDR, CONFIG_RAMBANK1_SIZE, + 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) +{ +#if (CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3) + uint64_t reg; + + /* Disable alignment fault checking */ + + reg = read_sysreg(sctlr_el3); + reg &= ~SCTLR_A_BIT; + write_sysreg(reg, sctlr_el3); + + /* At EL3, cntfrq_el0 is uninitialized. It must be set. */ + + write_sysreg(CONFIG_XPAR_CPU_CORTEXA53_0_TIMESTAMP_CLK_FREQ, cntfrq_el0); + ARM64_ISB(); +#endif +} + +#ifdef CONFIG_SMP + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_cpu_index + * + * Description: + * Return an index in the range of 0 through (CONFIG_SMP_NCPUS-1) that + * corresponds to the currently executing CPU. + * + * If TLS is enabled, then the RTOS can get this information from the TLS + * info structure. Otherwise, the MCU-specific logic must provide some + * mechanism to provide the CPU index. + * + * Input Parameters: + * None + * + * Returned Value: + * An integer index in the range of 0 through (CONFIG_SMP_NCPUS-1) that + * corresponds to the currently executing CPU. + * + ****************************************************************************/ + +int up_cpu_index(void) +{ + /* Read the Multiprocessor Affinity Register (MPIDR) + * And return the CPU ID field + */ + + return MPID_TO_CORE(GET_MPIDR(), 0); +} + +/**************************************************************************** + * Name: arm64_get_mpid + * + * Description: + * The function from cpu index to get cpu mpid which is reading + * from mpidr_el1 register. Different ARM64 Core will use different + * Affn define, the mpidr_el1 value is not CPU number, So we need + * to change CPU number to mpid and vice versa + * + ****************************************************************************/ + +uint64_t arm64_get_mpid(int cpu) +{ + return CORE_TO_MPID(cpu, 0); +} + +/**************************************************************************** + * Name: arm64_get_cpuid + * + * Description: + * The function from mpid to get cpu id + * + ****************************************************************************/ + +int arm64_get_cpuid(uint64_t mpid) +{ + return MPID_TO_CORE(mpid, 0); +} + +#endif /* CONFIG_SMP */ + +/**************************************************************************** + * 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); + +#if defined(CONFIG_SMP) || defined(CONFIG_ARCH_HAVE_PSCI) + /* arm64_psci_init("smc"); */ + +#endif + + /* Perform board-specific device initialization. This would include + * configuration of board specific resources such as GPIOs, LEDs, etc. + */ + + zynq_board_initialize(); + +#ifdef USE_EARLYSERIALINIT + /* Perform early serial initialization if we are going to use the serial + * driver. + */ + + arm64_earlyserialinit(); +#endif +} + +#if defined(CONFIG_NET) && !defined(CONFIG_NETDEV_LATEINIT) +void arm64_netinitialize(void) +{ + /* TODO: Support net initialize */ +} +#endif diff --git a/arch/arm64/src/zynq-mpsoc/zynq_boot.h b/arch/arm64/src/zynq-mpsoc/zynq_boot.h new file mode 100644 index 00000000000..6de1944629a --- /dev/null +++ b/arch/arm64/src/zynq-mpsoc/zynq_boot.h @@ -0,0 +1,77 @@ +/**************************************************************************** + * arch/arm64/src/zynq-mpsoc/zynq_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_ZYNQ_MPSOC_ZYNQ_BOOT_H +#define __ARCH_ARM64_SRC_ZYNQ_MPSOC_ZYNQ_BOOT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "arm64_internal.h" +#include "arm64_arch.h" + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: zynq_board_initialize + * + * Description: + * All zynq architectures must provide the following entry point. This + * entry point is called in the initialization phase -- after + * a64_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 zynq_board_initialize(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM64_SRC_ZYNQ_MPSOC_ZYNQ_BOOT_H */ diff --git a/arch/arm64/src/zynq-mpsoc/zynq_lowputc.S b/arch/arm64/src/zynq-mpsoc/zynq_lowputc.S new file mode 100644 index 00000000000..089606721e4 --- /dev/null +++ b/arch/arm64/src/zynq-mpsoc/zynq_lowputc.S @@ -0,0 +1,92 @@ +/**************************************************************************** + * arch/arm64/src/zynq-mpsoc/zynq_lowputc.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 + * Low-level console output for XilinX Zynq Mpsoc + * + ***************************************************************************/ + +#include + +#include "arm64_macro.inc" + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + .file "zynq_lowputc.S" + +/**************************************************************************** + * Assembly Macros + ****************************************************************************/ + + /* XilinX Zynq Mpsoc XCZU28DR UART0 Base Address */ +#define UART0_BASE_ADDRESS 0xff000000 +#define XUARTPS_SR_OFFSET 0x002CU /**< Channel Status [14:0] */ +#define XUARTPS_SR_TXFULL 0x0010U /**< TX FIFO full */ +#define XUARTPS_FIFO_OFFSET 0x0030U /**< FIFO [7:0] */ +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* Initialize Zynq Mpsoc UART + * xb: Register that contains the UART Base Address + * c: Scratch register number + */ + +GTEXT(arm64_earlyprintinit) +SECTION_FUNC(text, arm64_earlyprintinit) + ret /* Do nothing because U-Boot has already initialized UART */ + +/* Wait for XCZU28DR UART to be ready to transmit + * xb: Register that contains the UART Base Address + * wt: Scratch register number + */ + +.macro early_uart_ready xb, wt +1: + ldr \wt, [\xb, #XUARTPS_SR_OFFSET] /* UART_LSR (Line Status Register) */ + tst \wt, #XUARTPS_SR_TXFULL /* Check THRE (TX Holding Register Empty) */ + b.ne 1b /* Wait for the UART to be ready (THRE=1) */ +.endm + +/* Transmit character to XCZU28DR UART + * xb: Register that contains the UART base address + * wt: Register that contains the character to transmit + */ + +.macro early_uart_transmit xb, wt + str \wt, [\xb, #XUARTPS_FIFO_OFFSET] /* -> 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, =UART0_BASE_ADDRESS + early_uart_ready x15, w2 + early_uart_transmit x15, w0 + ret diff --git a/arch/arm64/src/zynq-mpsoc/zynq_serial.c b/arch/arm64/src/zynq-mpsoc/zynq_serial.c new file mode 100644 index 00000000000..9c3c7ce0bfc --- /dev/null +++ b/arch/arm64/src/zynq-mpsoc/zynq_serial.c @@ -0,0 +1,1372 @@ +/*************************************************************************** + * arch/arm64/src/zynq-mpsoc/zynq_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 "arm64_arch.h" +#include "arm64_internal.h" +#include "zynq_serial.h" +#include "arm64_arch_timer.h" +#include "zynq_boot.h" +#include "arm64_gic.h" + +#ifdef USE_SERIALDRIVER + +/*************************************************************************** + * Pre-processor Definitions + ***************************************************************************/ + +/* UART0 Settings should be same as U-Boot Bootloader */ + +#ifndef CONFIG_UART0_BAUD +# define CONFIG_UART0_BAUD 115200 +#endif + +#ifndef CONFIG_UART0_BITS +# define CONFIG_UART0_BITS 8 +#endif + +#ifndef CONFIG_UART0_PARITY +# define CONFIG_UART0_PARITY 0 +#endif + +#ifndef CONFIG_UART0_2STOP +# define CONFIG_UART0_2STOP 0 +#endif + +#ifndef CONFIG_UART0_RXBUFSIZE +# define CONFIG_UART0_RXBUFSIZE 256 +#endif + +#ifndef CONFIG_UART0_TXBUFSIZE +# define CONFIG_UART0_TXBUFSIZE 256 +#endif + +/* UART0 is console and ttyS0 */ + +#define CONSOLE_DEV g_uart0port /* UART0 is console */ +#define TTYS0_DEV g_uart0port /* UART0 is ttyS0 */ +#define UART0_ASSIGNED 1 + +/*************************************************************************** + * ZYNQ_MPSOC UART Registers and Bit Definitions + * + * Register Map + * + * Register offsets for the UART. + ***************************************************************************/ + +#define XUARTPS_CR_OFFSET 0x0000U /* Control Register [8:0] */ +#define XUARTPS_MR_OFFSET 0x0004U /* Mode Register [9:0] */ +#define XUARTPS_IER_OFFSET 0x0008U /* Interrupt Enable [12:0] */ +#define XUARTPS_IDR_OFFSET 0x000CU /* Interrupt Disable [12:0] */ +#define XUARTPS_IMR_OFFSET 0x0010U /* Interrupt Mask [12:0] */ +#define XUARTPS_ISR_OFFSET 0x0014U /* Interrupt Status [12:0]*/ +#define XUARTPS_BAUDGEN_OFFSET 0x0018U /* Baud Rate Generator [15:0] */ +#define XUARTPS_RXTOUT_OFFSET 0x001CU /* RX Timeout [7:0] */ +#define XUARTPS_RXWM_OFFSET 0x0020U /* RX FIFO Trigger Level [5:0] */ +#define XUARTPS_MODEMCR_OFFSET 0x0024U /* Modem Control [5:0] */ +#define XUARTPS_MODEMSR_OFFSET 0x0028U /* Modem Status [8:0] */ +#define XUARTPS_SR_OFFSET 0x002CU /* Channel Status [14:0] */ +#define XUARTPS_FIFO_OFFSET 0x0030U /* FIFO [7:0] */ +#define XUARTPS_BAUDDIV_OFFSET 0x0034U /* Baud Rate Divider [7:0] */ +#define XUARTPS_FLOWDEL_OFFSET 0x0038U /* Flow Delay [5:0] */ +#define XUARTPS_TXWM_OFFSET 0x0044U /* TX FIFO Trigger Level [5:0] */ +#define XUARTPS_RXBS_OFFSET 0x0048U /* RX FIFO Byte Status [11:0] */ + +/*************************************************************************** + * Control Register + * + * The Control register (CR) controls the major functions of the device. + * + * Control Register Bit Definition + ***************************************************************************/ + +#define XUARTPS_CR_STOPBRK 0x00000100U /* Stop transmission of break */ +#define XUARTPS_CR_STARTBRK 0x00000080U /* Set break */ +#define XUARTPS_CR_TORST 0x00000040U /* RX timeout counter restart */ +#define XUARTPS_CR_TX_DIS 0x00000020U /* TX disabled. */ +#define XUARTPS_CR_TX_EN 0x00000010U /* TX enabled */ +#define XUARTPS_CR_RX_DIS 0x00000008U /* RX disabled. */ +#define XUARTPS_CR_RX_EN 0x00000004U /* RX enabled */ +#define XUARTPS_CR_EN_DIS_MASK 0x0000003CU /* Enable/disable Mask */ +#define XUARTPS_CR_TXRST 0x00000002U /* TX logic reset */ +#define XUARTPS_CR_RXRST 0x00000001U /* RX logic reset */ + +/*************************************************************************** + * Mode Register + * + * The mode register (MR) defines the mode of transfer as well as the data + * format. If this register is modified during transmission or reception, + * data validity cannot be guaranteed. + * + * Mode Register Bit Definition + * + ***************************************************************************/ +#define XUARTPS_MR_CCLK 0x00000400U /* Input clock selection */ +#define XUARTPS_MR_CHMODE_R_LOOP 0x00000300U /* Remote loopback mode */ +#define XUARTPS_MR_CHMODE_L_LOOP 0x00000200U /* Local loopback mode */ +#define XUARTPS_MR_CHMODE_ECHO 0x00000100U /* Auto echo mode */ +#define XUARTPS_MR_CHMODE_NORM 0x00000000U /* Normal mode */ +#define XUARTPS_MR_CHMODE_SHIFT 8U /* Mode shift */ +#define XUARTPS_MR_CHMODE_MASK 0x00000300U /* Mode mask */ +#define XUARTPS_MR_STOPMODE_2_BIT 0x00000080U /* 2 stop bits */ +#define XUARTPS_MR_STOPMODE_1_5_BIT 0x00000040U /* 1.5 stop bits */ +#define XUARTPS_MR_STOPMODE_1_BIT 0x00000000U /* 1 stop bit */ +#define XUARTPS_MR_STOPMODE_SHIFT 6U /* Stop bits shift */ +#define XUARTPS_MR_STOPMODE_MASK 0x000000A0U /* Stop bits mask */ +#define XUARTPS_MR_PARITY_NONE 0x00000020U /* No parity mode */ +#define XUARTPS_MR_PARITY_MARK 0x00000018U /* Mark parity mode */ +#define XUARTPS_MR_PARITY_SPACE 0x00000010U /* Space parity mode */ +#define XUARTPS_MR_PARITY_ODD 0x00000008U /* Odd parity mode */ +#define XUARTPS_MR_PARITY_EVEN 0x00000000U /* Even parity mode */ +#define XUARTPS_MR_PARITY_SHIFT 3U /* Parity setting shift */ +#define XUARTPS_MR_PARITY_MASK 0x00000038U /* Parity mask */ +#define XUARTPS_MR_CHARLEN_6_BIT 0x00000006U /* 6 bits data */ +#define XUARTPS_MR_CHARLEN_7_BIT 0x00000004U /* 7 bits data */ +#define XUARTPS_MR_CHARLEN_8_BIT 0x00000000U /* 8 bits data */ +#define XUARTPS_MR_CHARLEN_SHIFT 1U /* Data Length shift */ +#define XUARTPS_MR_CHARLEN_MASK 0x00000006U /* Data length mask */ +#define XUARTPS_MR_CLKSEL 0x00000001U /* Input clock selection */ + +#define UART_DEFAULT_MODE XUARTPS_MR_CHMODE_NORM | \ + XUARTPS_MR_STOPMODE_1_BIT | \ + XUARTPS_MR_PARITY_NONE | \ + XUARTPS_MR_CHARLEN_8_BIT + +/*************************************************************************** + * Interrupt Registers + * + * Interrupt control logic uses the interrupt enable register (IER) and the + * interrupt disable register (IDR) to set the value of the bits in the + * interrupt mask register (IMR). The IMR determines whether to pass an + * interrupt to the interrupt status register (ISR). + * Writing a 1 to IER Enbables an interrupt, writing a 1 to IDR disables an + * interrupt. IMR and ISR are read only, and IER and IDR are write only. + * Reading either IER or IDR returns 0x00. + * + * All four registers have the same bit definitions. + * + ***************************************************************************/ + +#define XUARTPS_IXR_RBRK 0x00002000U /* Rx FIFO break detect interrupt */ +#define XUARTPS_IXR_TOVR 0x00001000U /* Tx FIFO Overflow interrupt */ +#define XUARTPS_IXR_TNFUL 0x00000800U /* Tx FIFO Nearly Full interrupt */ +#define XUARTPS_IXR_TTRIG 0x00000400U /* Tx Trig interrupt */ +#define XUARTPS_IXR_DMS 0x00000200U /* Modem status change interrupt */ +#define XUARTPS_IXR_TOUT 0x00000100U /* Timeout error interrupt */ +#define XUARTPS_IXR_PARITY 0x00000080U /* Parity error interrupt */ +#define XUARTPS_IXR_FRAMING 0x00000040U /* Framing error interrupt */ +#define XUARTPS_IXR_OVER 0x00000020U /* Overrun error interrupt */ +#define XUARTPS_IXR_TXFULL 0x00000010U /* TX FIFO full interrupt. */ +#define XUARTPS_IXR_TXEMPTY 0x00000008U /* TX FIFO empty interrupt. */ +#define XUARTPS_IXR_RXFULL 0x00000004U /* RX FIFO full interrupt. */ +#define XUARTPS_IXR_RXEMPTY 0x00000002U /* RX FIFO empty interrupt. */ +#define XUARTPS_IXR_RXOVR 0x00000001U /* RX FIFO trigger interrupt. */ +#define XUARTPS_IXR_MASK 0x00003FFFU /* Valid bit mask */ + +/*************************************************************************** + * Baud Rate Generator Register + * + * The baud rate generator control register (BRGR) is a 16 bit register that + * controls the receiver bit sample clock and baud rate. + * Valid values are 1 - 65535. + * + * Bit Sample Rate = CCLK / BRGR, where the CCLK is selected by the MR_CCLK + * bit in the MR register. + * + ***************************************************************************/ + +#define XUARTPS_BAUDGEN_DISABLE 0x00000000U /* Disable clock */ +#define XUARTPS_BAUDGEN_MASK 0x0000FFFFU /* Valid bits mask */ +#define XUARTPS_BAUDGEN_RESET_VAL 0x0000028BU /* Reset value */ + +/*************************************************************************** + * Baud Divisor Rate register + * + * The baud rate divider register (BDIV) controls how much the bit sample + * rate is divided by. It sets the baud rate. + * Valid values are 0x04 to 0xFF. Writing a value less than 4 will be + * ignored. + * + * Baud rate = CCLK / ((BAUDDIV + 1) x BRGR), where the CCLK is selected by + * the MR_CCLK bit in the MR register. + * + ***************************************************************************/ + +#define XUARTPS_BAUDDIV_MASK 0x000000FFU /* 8 bit baud divider mask */ +#define XUARTPS_BAUDDIV_RESET_VAL 0x0000000FU /* Reset value */ + +/*************************************************************************** + * The following constant defines the amount of error that is allowed for + * a specified baud rate. This error is the difference between the actual + * baud rate that will be generated using the specified clock and the + * desired baud rate. + ***************************************************************************/ + +#define XUARTPS_MAX_BAUD_ERROR_RATE 3U /* max % error allowed */ + +/*************************************************************************** + * The following constants indicate the max and min baud rates and these + * numbers are based only on the testing that has been done. The hardware + * is capable of other baud rates. + ***************************************************************************/ + +#define XUARTPS_MAX_RATE 6240000U +#define XUARTPS_MIN_RATE 110U + +/*************************************************************************** + * Receiver Timeout Register + * + * Use the receiver timeout register (RTR) to detect an idle condition on + * the receiver data line. + * + ***************************************************************************/ + +#define XUARTPS_RXTOUT_DISABLE 0x00000000U /* Disable time out */ +#define XUARTPS_RXTOUT_MASK 0x000000FFU /* Valid bits mask */ + +/*************************************************************************** + * Receiver FIFO Trigger Level Register + * + * Use the Receiver FIFO Trigger Level Register (RTRIG) to set the value at + * which the RX FIFO triggers an interrupt event. + * + ***************************************************************************/ + +#define XUARTPS_RXWM_DISABLE 0x00000000U /* Disable RX trigger interrupt */ +#define XUARTPS_RXWM_MASK 0x0000003FU /* Valid bits mask */ +#define XUARTPS_RXWM_RESET_VAL 0x00000020U /* Reset value */ + +/*************************************************************************** + * Transmit FIFO Trigger Level Register + * + * Use the Transmit FIFO Trigger Level Register (TTRIG) to set the value at + * which the TX FIFO triggers an interrupt event. + * + ***************************************************************************/ + +#define XUARTPS_TXWM_MASK 0x0000003FU /* Valid bits mask */ +#define XUARTPS_TXWM_RESET_VAL 0x00000020U /* Reset value */ + +/*************************************************************************** + * Modem Control Register + * + * This register (MODEMCR) controls the interface with the modem or data + * set, or a peripheral device emulating a modem. + * + ***************************************************************************/ + +#define XUARTPS_MODEMCR_FCM 0x00000020U /* Flow control mode */ +#define XUARTPS_MODEMCR_RTS 0x00000002U /* Request to send */ +#define XUARTPS_MODEMCR_DTR 0x00000001U /* Data terminal ready */ + +/*************************************************************************** + * Modem Status Register + * + * This register (MODEMSR) indicates the current state of the control lines + * from a modem, or another peripheral device, to the CPU. In addition, four + * bits of the modem status register provide change information. These bits + * are set to a logic 1 whenever a control input from the modem changes + * state. + * + * Note: Whenever the DCTS, DDSR, TERI, or DDCD bit is set to logic 1, a + * modem status interrupt is generated and this is reflected in the modem + * status register. + * + ***************************************************************************/ + +#define XUARTPS_MODEMSR_FCMS 0x00000100U /* Flow control mode (FCMS) */ +#define XUARTPS_MODEMSR_DCD 0x00000080U /* Complement of DCD input */ +#define XUARTPS_MODEMSR_RI 0x00000040U /* Complement of RI input */ +#define XUARTPS_MODEMSR_DSR 0x00000020U /* Complement of DSR input */ +#define XUARTPS_MODEMSR_CTS 0x00000010U /* Complement of CTS input */ +#define XUARTPS_MODEMSR_DDCD 0x00000008U /* Delta DCD indicator */ +#define XUARTPS_MODEMSR_TERI 0x00000004U /* Trailing Edge Ring Indicator */ +#define XUARTPS_MODEMSR_DDSR 0x00000002U /* Change of DSR */ +#define XUARTPS_MODEMSR_DCTS 0x00000001U /* Change of CTS */ + +/*************************************************************************** + * Channel Status Register + * + * The channel status register (CSR) is provided to enable the control logic + * to monitor the status of bits in the channel interrupt status register, + * even if these are masked out by the interrupt mask register. + * + ***************************************************************************/ + +#define XUARTPS_SR_TNFUL 0x00004000U /* TX FIFO Nearly Full Status */ +#define XUARTPS_SR_TTRIG 0x00002000U /* TX FIFO Trigger Status */ +#define XUARTPS_SR_FLOWDEL 0x00001000U /* RX FIFO fill over flow delay */ +#define XUARTPS_SR_TACTIVE 0x00000800U /* TX active */ +#define XUARTPS_SR_RACTIVE 0x00000400U /* RX active */ +#define XUARTPS_SR_TXFULL 0x00000010U /* TX FIFO full */ +#define XUARTPS_SR_TXEMPTY 0x00000008U /* TX FIFO empty */ +#define XUARTPS_SR_RXFULL 0x00000004U /* RX FIFO full */ +#define XUARTPS_SR_RXEMPTY 0x00000002U /* RX FIFO empty */ +#define XUARTPS_SR_RXOVR 0x00000001U /* RX FIFO fill over trigger */ + +/*************************************************************************** + * Flow Delay Register + * + * Operation of the flow delay register (FLOWDEL) is very similar to the + * receive FIFO trigger register. An internal trigger signal activates when + * the FIFO is filled to the level set by this register. This trigger will + * not cause an interrupt, although it can be read through the channel + * status register. In hardware flow control mode, RTS is deactivated when + * the trigger becomes active. RTS only resets when the FIFO level is four + * less than the level of the flow delay trigger and the flow delay trigger + * is not activated. A value less than 4 disables the flow delay. + * + ***************************************************************************/ + +#define XUARTPS_FLOWDEL_MASK XUARTPS_RXWM_MASK /* Valid bit mask */ + +/*************************************************************************** + * Receiver FIFO Byte Status Register + * + * The Receiver FIFO Status register is used to have a continuous + * monitoring of the raw unmasked byte status information. The register + * contains frame, parity and break status information for the top + * four bytes in the RX FIFO. + * + * Receiver FIFO Byte Status Register Bit Definition + * + ***************************************************************************/ + +#define XUARTPS_RXBS_BYTE3_BRKE 0x00000800U /* Byte3 Break Error */ +#define XUARTPS_RXBS_BYTE3_FRME 0x00000400U /* Byte3 Frame Error */ +#define XUARTPS_RXBS_BYTE3_PARE 0x00000200U /* Byte3 Parity Error */ +#define XUARTPS_RXBS_BYTE2_BRKE 0x00000100U /* Byte2 Break Error */ +#define XUARTPS_RXBS_BYTE2_FRME 0x00000080U /* Byte2 Frame Error */ +#define XUARTPS_RXBS_BYTE2_PARE 0x00000040U /* Byte2 Parity Error */ +#define XUARTPS_RXBS_BYTE1_BRKE 0x00000020U /* Byte1 Break Error */ +#define XUARTPS_RXBS_BYTE1_FRME 0x00000010U /* Byte1 Frame Error */ +#define XUARTPS_RXBS_BYTE1_PARE 0x00000008U /* Byte1 Parity Error */ +#define XUARTPS_RXBS_BYTE0_BRKE 0x00000004U /* Byte0 Break Error */ +#define XUARTPS_RXBS_BYTE0_FRME 0x00000002U /* Byte0 Frame Error */ +#define XUARTPS_RXBS_BYTE0_PARE 0x00000001U /* Byte0 Parity Error */ +#define XUARTPS_RXBS_MASK 0x00000007U /* 3 bit RX byte status mask */ + +/*************************************************************************** + * Private Types + ***************************************************************************/ + +/* ZYNQ_MPSOC UART Configuration */ + +struct zynq_uart_config +{ + unsigned long uart; /* UART Base Address */ +}; + +/* ZYNQ_MPSOC UART Device Data */ + +struct zynq_uart_data +{ + uint32_t baud_rate; /* UART Baud Rate */ + uint32_t ier; /* Saved IER value */ + uint8_t parity; /* 0=none, 1=odd, 2=even */ + uint8_t bits; /* Number of bits (7 or 8) */ + bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */ +}; + +/* ZYNQ_MPSOC UART Port */ + +struct zynq_uart_port_s +{ + struct zynq_uart_data data; /* UART Device Data */ + struct zynq_uart_config config; /* UART Configuration */ + unsigned int irq_num; /* UART IRQ Number */ + bool is_console; /* 1 if this UART is console */ +}; + +/*************************************************************************** + * Private Function Prototypes + ***************************************************************************/ + +static void zynq_uart_rxint(struct uart_dev_s *dev, bool enable); +static void zynq_uart_txint(struct uart_dev_s *dev, bool enable); + +/*************************************************************************** + * Private Functions + ***************************************************************************/ + +/*************************************************************************** + * Name: zynq_uart_irq_handler + * + * Description: + * This is the common UART interrupt handler. It should call + * uart_xmitchars or uart_recvchars to perform the appropriate data + * transfers. + * + * Input Parameters: + * irq - IRQ Number + * context - Interrupt Context + * arg - UART Device + * + * Returned Value: + * OK is always returned at present. + * + ***************************************************************************/ + +static int zynq_uart_irq_handler(int irq, void *context, void *arg) +{ + struct uart_dev_s *dev = (struct uart_dev_s *)arg; + struct zynq_uart_port_s *port = (struct zynq_uart_port_s *)dev->priv; + struct zynq_uart_config *config = &port->config; + uint32_t status; + + DEBUGASSERT(dev != NULL && dev->priv != NULL); + + status = getreg32(config->uart + XUARTPS_ISR_OFFSET); + putreg32(status, (config->uart + XUARTPS_ISR_OFFSET)); + + if (status & XUARTPS_IXR_FRAMING) + { + while (!(getreg32(config->uart + XUARTPS_SR_OFFSET) & + XUARTPS_SR_RXEMPTY)) + { + if (!getreg8(config->uart + XUARTPS_FIFO_OFFSET)) + { + status &= ~XUARTPS_IXR_FRAMING; + } + } + + putreg32(XUARTPS_IXR_FRAMING, (config->uart + XUARTPS_ISR_OFFSET)); + } + + if (status & XUARTPS_IXR_TXEMPTY) + { + uart_xmitchars(dev); + } + + if (status & (XUARTPS_IXR_RXOVR | XUARTPS_IXR_TOUT | XUARTPS_IXR_RXFULL)) + { + while (1) + { + if ((getreg32(config->uart + XUARTPS_SR_OFFSET) & + XUARTPS_SR_RXEMPTY) == XUARTPS_SR_RXEMPTY) + { + break; + } + else + { + uart_recvchars(dev); + } + } + } + + return OK; +} + +static int zynq_uart_baudrate(struct uart_dev_s *dev, uint32_t in_clk) +{ + struct zynq_uart_port_s *port = (struct zynq_uart_port_s *)dev->priv; + const struct zynq_uart_config *config = &port->config; + struct zynq_uart_data *data = &port->data; + uint32_t iter_baud_div; /* Iterator for available baud divisor values */ + uint32_t brgr_value; /* Calculated value for baud rate generator */ + uint32_t calc_baudrate; /* Calculated baud rate */ + uint32_t baud_error; /* Diff between calculated and requested baud rate */ + uint32_t best_brgr = 0U; /* Best value for baud rate generator */ + uint8_t best_baud_div = 0U; /* Best value for baud divisor */ + uint32_t best_error = 0xffffffff; + uint32_t percent_error; + uint32_t reg; + uint32_t input_clk; + uint32_t temp_reg; + + /* Asserts validate the input arguments */ + + DEBUGASSERT(data->baud_rate <= (uint32_t)XUARTPS_MAX_RATE); + DEBUGASSERT(data->baud_rate >= (uint32_t)XUARTPS_MIN_RATE); + + /* Make sure the baud rate is not impossilby large. + * Fastest possible baud rate is Input Clock / 2. + */ + + if ((data->baud_rate * 2) > in_clk) + { + return ERROR; + } + + /* Check whether the input clock is divided by 8 */ + + reg = getreg32(config->uart + XUARTPS_MR_OFFSET); + + input_clk = in_clk; + if (reg & XUARTPS_MR_CLKSEL) + { + input_clk = in_clk / 8; + } + + /* Determine the Baud divider. It can be 4to 254. + * Loop through all possible combinations + */ + + for (iter_baud_div = 4; iter_baud_div < 255; iter_baud_div++) + { + /* Calculate the value for BRGR register */ + + brgr_value = input_clk / (data->baud_rate * (iter_baud_div + 1)); + + /* Calculate the baud rate from the BRGR value */ + + calc_baudrate = input_clk / (brgr_value * (iter_baud_div + 1)); + + /* Avoid unsigned integer underflow */ + + if (data->baud_rate > calc_baudrate) + { + baud_error = data->baud_rate - calc_baudrate; + } + else + { + baud_error = calc_baudrate - data->baud_rate; + } + + /* Find the calculated baud rate closest to requested baud rate. */ + + if (best_error > baud_error) + { + best_brgr = brgr_value; + best_baud_div = iter_baud_div; + best_error = baud_error; + } + } + + /* Make sure the best error is not too large. */ + + percent_error = (best_error * 100) / data->baud_rate; + if (XUARTPS_MAX_BAUD_ERROR_RATE < percent_error) + { + return ERROR; + } + + /* Disable TX and RX to avoid glitches when setting the baud rate. */ + + temp_reg = (((getreg32(config->uart + XUARTPS_CR_OFFSET)) & + ((uint32_t)(~XUARTPS_CR_EN_DIS_MASK))) | + ((uint32_t)XUARTPS_CR_RX_DIS | (uint32_t)XUARTPS_CR_TX_DIS)); + putreg32(temp_reg, config->uart + XUARTPS_CR_OFFSET); + + /* Set the baud rate divisor */ + + putreg32(best_brgr, config->uart + XUARTPS_BAUDGEN_OFFSET); + putreg32(best_baud_div, config->uart + XUARTPS_BAUDDIV_OFFSET); + + /* RX and TX SW reset */ + + putreg32(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST, + config->uart + XUARTPS_CR_OFFSET); + + /* Enable device */ + + temp_reg = (((getreg32(config->uart + XUARTPS_CR_OFFSET)) & + ((uint32_t)(~XUARTPS_CR_EN_DIS_MASK))) | + ((uint32_t)XUARTPS_CR_RX_EN | (uint32_t)XUARTPS_CR_TX_EN)); + putreg32(temp_reg, config->uart + XUARTPS_CR_OFFSET); + + return OK; +} + +/*************************************************************************** + * Name: zynq_uart_setup + * + * Description: + * Configure the UART baud, bits, parity, fifos, etc. This method is + * called the first time that the serial port is opened. + * + * Input Parameters: + * dev - UART Device + * + * Returned Value: + * Zero (OK) on success; a negated errno value is returned on any failure. + * + ***************************************************************************/ + +static int zynq_uart_setup(struct uart_dev_s *dev) +{ +#ifndef CONFIG_SUPPRESS_UART_CONFIG + struct zynq_uart_port_s *port = (struct zynq_uart_port_s *)dev->priv; + const struct zynq_uart_config *config = &port->config; + struct zynq_uart_data *data = &port->data; + uint32_t reg = 0U; + + DEBUGASSERT(data != NULL); + + if (zynq_uart_baudrate(dev, CONFIG_XPAR_PSU_UART_0_UART_CLK_FREQ_HZ) + != OK) + { + return ERROR; + } + + /* Set the parity mode */ + + reg = getreg32(config->uart + XUARTPS_MR_OFFSET); + + /* Mask off what's already there */ + + reg &= (~((uint32_t)XUARTPS_MR_CHARLEN_MASK | + (uint32_t)XUARTPS_MR_STOPMODE_MASK | + (uint32_t)XUARTPS_MR_PARITY_MASK)); + + switch (data->bits) + { + case 6: + reg |= (uint32_t)XUARTPS_MR_CHARLEN_6_BIT; + break; + case 7: + reg |= (uint32_t)XUARTPS_MR_CHARLEN_7_BIT; + break; + case 8: + reg |= (uint32_t)XUARTPS_MR_CHARLEN_8_BIT; + break; + default: + reg |= (uint32_t)XUARTPS_MR_CHARLEN_8_BIT; + break; + } + + if (data->stopbits2) + { + reg |= (uint32_t)XUARTPS_MR_STOPMODE_2_BIT; + } + else + { + reg |= (uint32_t)XUARTPS_MR_STOPMODE_1_BIT; + } + + switch (data->parity) + { + case 0: + reg |= (uint32_t)XUARTPS_MR_PARITY_NONE; + break; + case 1: + reg |= (uint32_t)XUARTPS_MR_PARITY_ODD; + break; + case 2: + reg |= (uint32_t)XUARTPS_MR_PARITY_EVEN; + break; + default: + reg |= (uint32_t)XUARTPS_MR_PARITY_NONE; + break; + } + + /* Write the mode register out */ + + putreg32(reg, config->uart + XUARTPS_MR_OFFSET); + + /* Set the RX FIFO trigger at 8 data bytes. */ + + putreg32(0x08, config->uart + XUARTPS_RXWM_OFFSET); + + /* Set the RX timeout to 1, which will be 4 character time */ + + putreg32(0x01, config->uart + XUARTPS_RXTOUT_OFFSET); + + /* Disable all interrupts, polled mode is the default */ + + putreg32(XUARTPS_IXR_MASK, config->uart + XUARTPS_IDR_OFFSET); + +#endif /* CONFIG_SUPPRESS_UART_CONFIG */ + return OK; +} + +/*************************************************************************** + * Name: zynq_uart_shutdown + * + * Description: + * Disable the UART Port. This method is called when the serial + * port is closed. + * + * Input Parameters: + * dev - UART Device + * + * Returned Value: + * None + * + ***************************************************************************/ + +static void zynq_uart_shutdown(struct uart_dev_s *dev) +{ + /* Disable the Receive and Transmit Interrupts */ + + zynq_uart_rxint(dev, false); + zynq_uart_txint(dev, false); +} + +/*************************************************************************** + * Name: zynq_uart_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. + * + * Input Parameters: + * dev - UART Device + * + * Returned Value: + * Zero (OK) on success; a negated errno value is returned on any failure. + * + ***************************************************************************/ + +static int zynq_uart_attach(struct uart_dev_s *dev) +{ + int ret; + struct zynq_uart_port_s *port = (struct zynq_uart_port_s *)dev->priv; + + DEBUGASSERT(port != NULL); + + /* Attach UART Interrupt Handler */ + + ret = irq_attach(port->irq_num, zynq_uart_irq_handler, dev); + + /* Set Interrupt Priority in Generic Interrupt Controller v2 */ + + arm64_gic_irq_set_priority(port->irq_num, 0, IRQ_TYPE_LEVEL); + + /* Enable UART Interrupt */ + + if (ret == OK) + { + up_enable_irq(port->irq_num); + } + else + { + _err("IRQ attach failed, ret=%d\n", ret); + } + + return ret; +} + +/*************************************************************************** + * Name: zynq_uart_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. + * + * Input Parameters: + * dev - UART Device + * + * Returned Value: + * None + * + ***************************************************************************/ + +static void zynq_uart_detach(struct uart_dev_s *dev) +{ + struct zynq_uart_port_s *port = (struct zynq_uart_port_s *)dev->priv; + + DEBUGASSERT(port != NULL); + + /* Disable UART Interrupt */ + + up_disable_irq(port->irq_num); + + /* Detach UART Interrupt Handler */ + + irq_detach(port->irq_num); +} + +/*************************************************************************** + * Name: zynq_uart_ioctl + * + * Description: + * All ioctl calls will be routed through this method. + * + * Input Parameters: + * filep - File Struct + * cmd - ioctl Command + * arg - ioctl Argument + * + * Returned Value: + * Zero (OK) on success; a negated errno value is returned on any failure. + * + ***************************************************************************/ + +static int zynq_uart_ioctl(struct file *filep, int cmd, unsigned long arg) +{ + int ret = OK; + + UNUSED(filep); + UNUSED(arg); + + switch (cmd) + { + case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ + case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ + default: + { + ret = -ENOTTY; + break; + } + } + + return ret; +} + +/*************************************************************************** + * Name: zynq_uart_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'. + * + * Input Parameters: + * dev - UART Device + * status - Return status, zero on success + * + * Returned Value: + * Received character + * + ***************************************************************************/ + +static int zynq_uart_receive(struct uart_dev_s *dev, unsigned int *status) +{ + struct zynq_uart_port_s *port = (struct zynq_uart_port_s *)dev->priv; + const struct zynq_uart_config *config = &port->config; + uint32_t rbr; + + *status = getreg8(config->uart + XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY; + + /* Wait until there is data */ + + if (*status) + { + return -1; + } + + rbr = getreg8(config->uart + XUARTPS_FIFO_OFFSET); + return rbr; +} + +/*************************************************************************** + * Name: zynq_uart_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + * Input Parameters: + * dev - UART Device + * enable - True to enable RX interrupts; false to disable + * + * Returned Value: + * None + * + ***************************************************************************/ + +static void zynq_uart_rxint(struct uart_dev_s *dev, bool enable) +{ + struct zynq_uart_port_s *port = (struct zynq_uart_port_s *)dev->priv; + struct zynq_uart_config *config = &port->config; + + /* Write to Interrupt Enable Register (UART_IER) */ + + if (enable) + { + /* Write the new value for the FIFO control register to it such that + * the threshold is changed + */ + + putreg32(1, config->uart + XUARTPS_RXWM_OFFSET); + + /* Set XUARTPS_IXR_RXOVR bit (Enable Rx Data Available Interrupt) */ + + modreg32(XUARTPS_IXR_RXOVR, XUARTPS_IXR_RXOVR, + config->uart + XUARTPS_IER_OFFSET); + + modreg32(0, XUARTPS_IXR_RXOVR, config->uart + XUARTPS_IDR_OFFSET); + + /* Set XUARTPS_IXR_RXFULL bit (Enable RxFifo full Interrupt) */ + + modreg32(XUARTPS_IXR_RXFULL, XUARTPS_IXR_RXFULL, + config->uart + XUARTPS_IER_OFFSET); + + modreg32(0, XUARTPS_IXR_RXFULL, config->uart + XUARTPS_IDR_OFFSET); + } + else + { + /* Set XUARTPS_IXR_RXOVR bit (Enable Rx Data Available Interrupt) */ + + modreg32(0, XUARTPS_IXR_RXOVR, config->uart + XUARTPS_IER_OFFSET); + modreg32(XUARTPS_IXR_RXOVR, XUARTPS_IXR_RXOVR, + config->uart + XUARTPS_IDR_OFFSET); + + /* Set XUARTPS_IXR_RXFULL bit (Enable RxFifo full Interrupt) */ + + modreg32(0, XUARTPS_IXR_RXFULL, config->uart + XUARTPS_IER_OFFSET); + modreg32(XUARTPS_IXR_RXFULL, XUARTPS_IXR_RXFULL, + config->uart + XUARTPS_IDR_OFFSET); + } +} + +/*************************************************************************** + * Name: zynq_uart_rxavailable + * + * Description: + * Return true if the Receive FIFO is not empty + * + * Input Parameters: + * dev - UART Device + * + * Returned Value: + * True if the Receive FIFO is not empty; false otherwise + * + ***************************************************************************/ + +static bool zynq_uart_rxavailable(struct uart_dev_s *dev) +{ + struct zynq_uart_port_s *port = (struct zynq_uart_port_s *)dev->priv; + struct zynq_uart_config *config = &port->config; + + /* RxFifo empty bit is 1 if Rx Data is unavailable */ + + return ((getreg8(config->uart + XUARTPS_SR_OFFSET) & + XUARTPS_SR_RXEMPTY) == 0); +} + +/*************************************************************************** + * Name: zynq_uart_send + * + * Description: + * This method will send one byte on the UART + * + * Input Parameters: + * dev - UART Device + * ch - Character to be sent + * + * Returned Value: + * None + * + ***************************************************************************/ + +static void zynq_uart_send(struct uart_dev_s *dev, int ch) +{ + struct zynq_uart_port_s *port = (struct zynq_uart_port_s *)dev->priv; + struct zynq_uart_config *config = &port->config; + + /* Write char to Transmit FIFO Register */ + + putreg8(ch, config->uart + XUARTPS_FIFO_OFFSET); +} + +/*************************************************************************** + * Name: zynq_uart_txint + * + * Description: + * Call to enable or disable TX interrupts + * + * Input Parameters: + * dev - UART Device + * enable - True to enable TX interrupts; false to disable + * + * Returned Value: + * None + * + ***************************************************************************/ + +static void zynq_uart_txint(struct uart_dev_s *dev, bool enable) +{ + struct zynq_uart_port_s *port = (struct zynq_uart_port_s *)dev->priv; + struct zynq_uart_config *config = &port->config; + + /* Write to Interrupt Enable Register (UART_IER) */ + + if (enable) + { + /* Set XUARTPS_IXR_TXEMPTY bit (Enable Tx Fifo Empty Interrupt) */ + + modreg32(XUARTPS_IXR_TXEMPTY, XUARTPS_IXR_TXEMPTY, + config->uart + XUARTPS_IER_OFFSET); + + modreg32(0, XUARTPS_IXR_TXEMPTY, config->uart + XUARTPS_IDR_OFFSET); + + /* Fake a TX interrupt */ + + uart_xmitchars(dev); + } + else + { + /* Clear XUARTPS_IXR_TXEMPTY bit (Disable Tx Fifo Empty Interrupt) */ + + modreg32(0, XUARTPS_IXR_TXEMPTY, config->uart + XUARTPS_IER_OFFSET); + modreg32(XUARTPS_IXR_TXEMPTY, XUARTPS_IXR_TXEMPTY, + config->uart + XUARTPS_IDR_OFFSET); + } +} + +/*************************************************************************** + * Name: zynq_uart_txready + * + * Description: + * Return true if the Transmit FIFO is not full + * + * Input Parameters: + * dev - UART Device + * + * Returned Value: + * True if the Transmit FIFO is not full; false otherwise + * + ***************************************************************************/ + +static bool zynq_uart_txready(struct uart_dev_s *dev) +{ + struct zynq_uart_port_s *port = (struct zynq_uart_port_s *)dev->priv; + struct zynq_uart_config *config = &port->config; + + /* Tx FIFO is ready if THRE Bit is 1 (Tx Holding Register Empty) */ + + return (getreg8(config->uart + XUARTPS_SR_OFFSET) + & XUARTPS_SR_TXFULL) == 0; +} + +/*************************************************************************** + * Name: zynq_uart_txempty + * + * Description: + * Return true if the Transmit FIFO is empty + * + * Input Parameters: + * dev - UART Device + * + * Returned Value: + * True if the Transmit FIFO is empty; false otherwise + * + ***************************************************************************/ + +static bool zynq_uart_txempty(struct uart_dev_s *dev) +{ + /* Tx FIFO is empty if Tx FIFO is not full (for now) */ + + return zynq_uart_txready(dev); +} + +/*************************************************************************** + * Name: zynq_uart_wait_send + * + * Description: + * Wait for Transmit FIFO until it is not full, then transmit the + * character over UART. + * + * Input Parameters: + * dev - UART Device + * ch - Character to be sent + * + * Returned Value: + * None + * + ***************************************************************************/ + +static void zynq_uart_wait_send(struct uart_dev_s *dev, int ch) +{ + DEBUGASSERT(dev != NULL); + while (!zynq_uart_txready(dev)); + zynq_uart_send(dev, ch); +} + +/*************************************************************************** + * Private Data + ***************************************************************************/ + +/* UART Operations for Serial Driver */ + +static const struct uart_ops_s g_uart_ops = +{ + .setup = zynq_uart_setup, + .shutdown = zynq_uart_shutdown, + .attach = zynq_uart_attach, + .detach = zynq_uart_detach, + .ioctl = zynq_uart_ioctl, + .receive = zynq_uart_receive, + .rxint = zynq_uart_rxint, + .rxavailable = zynq_uart_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = NULL, +#endif + .send = zynq_uart_send, + .txint = zynq_uart_txint, + .txready = zynq_uart_txready, + .txempty = zynq_uart_txempty, +}; + +#ifdef CONFIG_ZYNQ_MPSOC_UART0 + +/* UART0 Port State (Console) */ + +static struct zynq_uart_port_s g_uart0priv = +{ + .data = + { + .baud_rate = CONFIG_UART0_BAUD, + .parity = CONFIG_UART0_PARITY, + .bits = CONFIG_UART0_BITS, + .stopbits2 = CONFIG_UART0_2STOP + }, + + .config = + { + .uart = ZYNQ_MPSOC_UART0_ADDR + }, + + .irq_num = ZYNQ_MPSOC_IRQ_UART0, + .is_console = 1 +}; + +/* UART0 I/O Buffers (Console) */ + +static char g_uart0rxbuffer[CONFIG_UART0_RXBUFSIZE]; +static char g_uart0txbuffer[CONFIG_UART0_TXBUFSIZE]; + +/* UART0 Port Definition (Console) */ + +static struct uart_dev_s g_uart0port = +{ + .recv = + { + .size = CONFIG_UART0_RXBUFSIZE, + .buffer = g_uart0rxbuffer, + }, + + .xmit = + { + .size = CONFIG_UART0_TXBUFSIZE, + .buffer = g_uart0txbuffer, + }, + + .ops = &g_uart_ops, + .priv = &g_uart0priv, +}; + +#endif /* CONFIG_ZYNQ_MPSOC_UART */ + +#ifdef CONFIG_ZYNQ_MPSOC_UART1 + +/* UART1 Port State */ + +static struct zynq_uart_port_s g_uart1priv = +{ + .data = + { + .baud_rate = CONFIG_UART1_BAUD, + .parity = CONFIG_UART1_PARITY, + .bits = CONFIG_UART1_BITS, + .stopbits2 = CONFIG_UART1_2STOP + }, + + .config = + { + .uart = ZYNQ_MPSOC_UART1_ADDR + }, + + .irq_num = ZYNQ_MPSOC_IRQ_UART1, + .is_console = 0 +}; + +/* UART1 I/O Buffers */ + +static char g_uart1rxbuffer[CONFIG_UART1_RXBUFSIZE]; +static char g_uart1txbuffer[CONFIG_UART1_TXBUFSIZE]; + +/* UART1 Port Definition */ + +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 /* CONFIG_ZYNQ_MPSOC_UART1 */ + +/* Pick ttys1. This could be any of UART1. */ + +#if defined(CONFIG_ZYNQ_MPSOC_UART1) && !defined(UART1_ASSIGNED) +# define TTYS1_DEV g_uart1port /* UART1 is ttyS1 */ +# define UART1_ASSIGNED 1 +#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. + * + * Returned Value: + * None + * + ***************************************************************************/ + +void arm64_earlyserialinit(void) +{ + int ret; + + /* NOTE: This function assumes that UART0 low level hardware configuration + * -- including all clocking and pin configuration + */ + +#ifdef CONFIG_ZYNQ_MPSOC_UART1 + /* Configure UART1 */ + + ret = zynq_uart_setup(&g_uart1port); + if (ret < 0) + { + _err("UART1 config failed, ret=%d\n", ret); + } +#endif /* CONFIG_ZYNQ_MPSOC_UART1 */ + +#ifdef CONSOLE_DEV + /* Enable the console at UART0 */ + + CONSOLE_DEV.isconsole = true; + zynq_uart_setup(&CONSOLE_DEV); +#endif + + UNUSED(ret); +} + +/*************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug + * writes + * + * Input Parameters: + * ch - Character to be transmitted over UART + * + * Returned Value: + * Character that was transmitted + * + ***************************************************************************/ + +int up_putc(int ch) +{ +#ifdef CONSOLE_DEV + struct uart_dev_s *dev = &CONSOLE_DEV; + + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + zynq_uart_wait_send(dev, '\r'); + } + + zynq_uart_wait_send(dev, ch); +#endif + return ch; +} + +/*************************************************************************** + * Name: arm64_serialinit + * + * Description: + * Register serial console and serial ports. This assumes + * that zynq_earlyserialinit was called previously. + * + * Returned Value: + * None + * + ***************************************************************************/ + +void arm64_serialinit(void) +{ +#ifdef CONSOLE_DEV + int ret; + + ret = uart_register("/dev/console", &CONSOLE_DEV); + if (ret < 0) + { + _err("Register /dev/console failed, ret=%d\n", ret); + } + + ret = uart_register("/dev/ttyS0", &TTYS0_DEV); + + if (ret < 0) + { + _err("Register /dev/ttyS0 failed, ret=%d\n", ret); + } + +#ifdef TTYS1_DEV + ret = uart_register("/dev/ttyS1", &TTYS1_DEV); + + if (ret < 0) + { + _err("Register /dev/ttyS1 failed, ret=%d\n", ret); + } +#endif /* TTYS1_DEV */ + +#endif +} + +#endif /* USE_SERIALDRIVER */ diff --git a/arch/arm64/src/zynq-mpsoc/zynq_serial.h b/arch/arm64/src/zynq-mpsoc/zynq_serial.h new file mode 100644 index 00000000000..ddd443aab41 --- /dev/null +++ b/arch/arm64/src/zynq-mpsoc/zynq_serial.h @@ -0,0 +1,57 @@ +/**************************************************************************** + * arch/arm64/src/zynq-mpsoc/zynq_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_ZYNQ_MPSOC_ZYNQ_SERIAL_H +#define __ARCH_ARM64_ZYNQ_MPSOC_ZYNQ_SERIAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "arm64_internal.h" +#include "arm64_gic.h" +#include "hardware/zynq_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM64_ZYNQ_MPSOC_ZYNQ_SERIAL_H */