ARMv7 Cortex-A port for Xilinx Zynq7000


Immo Birnbaum
 

Hi,

I've been following the development of Zephyr ever since I attended the Embedded World in Nuremberg back in 2016, and I'd like to thank all those who have contributed to the system's current feature set and hardware support. The whole set of what the system now offers has made Zephyr a very attractive RTOS not only to me, but also to my employer, who has become interested in using it for several projects in the IoT field. The only catch is that one of our target hardware platforms is not yet supported, not only at the board/SoC level, but at the architecture level. We'd very much like to see Zephyr run on the dual core (SMP isn't a requirement, though) Cortex-A9 contained in the Xilinx Zynq7000 SoC, despite the lacking support for ARMv7 Cortex-A CPUs.

So I've sat down, equipped with a Digilent Zedboard which to my knowledge can still be considered the de-facto standard evaluation board for the Zynq7000 and is readily available and a Lauterbach debugger, and started porting Zephyr to the v7/Cortex-A architecture. I considered this to be an interesting challenge as although I've used ARM-based systems for quite some time now (all the way back to my trusty ol' Apple Newton), my past development experience is on x86- and PowerPC-based systems and RTOSes like QNX or eCos.

I'm now at a point at which I'd call the progress I've made up to now a working proof of concept. Here's what I've done so far:

- Added cortex_a to arch/arm/core, derived from the cortex_r implementation.
- Added Zynq7000 SoC and Zedboard definitions plus device trees.
- Implemented a simple driver for the GIC PL-390 interrupt controller.
- Re-used the existing Xilinx TTC and UART drivers.
- Implemented a driver for the Xilinx GEM GBit Ethernet controller, which includes PHY initialization via MDIO and link monitoring. The PHY part contains some register accesses specific to the Marvell PHY used on the Zedboard, but just the PHY reset and auto-negotiation management is generic. All of the driver's features are configurable via menuconfig.
- Implemented an interrupt-capable driver for the Xilinx AXI GPIO IP core, as the Zedboard features switches, pushbuttons and LEDs connected to the processor core via this IP core in the programmable logic part of the system.
- A driver for GPIO connected via the EMIO interface shouldn't be too hard either, although the number of available pins might be an issue here. The AXI GPIO driver is limited to single channel operation (the IP core has an optional 2nd channel) as e.g. the pin mask of the GPIO callback struct are limited to 32 bits.
- Enabled FPU support and saving of the FPU's registers during a context switch. The register saving is unconditional as Cortex-A doesn't seem to have an equivalent to the Cortex-M's CONTROL register and the flag indicating that the FPU registers are currently in use. With the GNU ARM Embedded Toolchain that I'm currently using, the FPU works using the softfp ABI.
- The MMU is set up in the simplest possible way, with a page table consisting of nothing but 1 MB page entries. The part of the system's memory map where the RAM is located is configured as cacheable/bufferable, which is a requirement for any unaligned accesses (which can for example be found in the IP stack) to work. If the MMU isn't set up this way, the result is an illegal instruction exception. The rest of the memory map is set up as strongly ordered, covering areas such as the SLCR, the peripherial register space and the OCM.
- Added a corresponding QEMU target using the Zynq7000 template.

Still, the to-do-list has a quite a few points on it:

- CMSIS for Cortex-A is not yet integrated, e.g. SLCR or FPU register accesses are hand-coded.
- Caches not activated yet, as my own driver implementations don't contain any barriers yet where they probably should have some.
- Only compiled with the GNU ARM Embedded Toolchain so far.
- QEMU only tested to the point where the hello world and philosophers demos are apparently working with a basic IRQ/Timer/UART setup.
- No tests from the testsuite have run so far.
- SMP not addressed at all, but this feature isn't that important to me personally. A single 666 MHz core is quite capable by itself...
- None of the security features are addressed, it's all secure mode-only for now.
- The interrupt controller uses the same workaround as the GIC PL-400 in the Cortex-R port: store a pointer to the driver attached to vector [0] as there is no well-defined interrupt controller such as the Cortex-M's NVIC. Therefore, currently all interrupt vectors are offset by one.
- No high-level/scripted configuration of the MMU possible for now.
- I'm currently forcing the ARM instruction set, there's currently no Thumb code being generated.
- I haven't yet looked into whether any other FP ABIs can be supported or not, and there are currently no configuration options for the FPU such as on how to handle denormals.
- Last but not least, the Zynq has some more peripherials generally supported by Zephyr but for which no drivers exist for now. As the processor system in the Zynq usually relies on *some* content in the programmable logic part (e.g. the AXI GPIO IP core), a driver for the Xilinx devcfg interface might be an integral part of the SoC support (although u-boot can handle this just as well), but there's also things like CAN, ADC, SPI, and the Zedboard features an OLED display...

I'd like to contribute my work to the project, is this of any interest to all of you? Are there any must-have items I should tackle beforehand, probably most likely regaring testing? If so, I'd probably have to start merging my modifications into the current code base, as I'm still working on a code base acquired shortly before the arch/arm path was split up into AARCH32 and AARCH64. What would be the next steps in providing this to the community, considering that this is a bit more than just a stand-alone device driver?

Best regards from Germany,
Immo

Join devel@lists.zephyrproject.org to automatically receive all group messages.