Skip to content

Staging/capi selftest#3206

Draft
cristina-suteu wants to merge 29 commits into
mainfrom
staging/capi-selftest
Draft

Staging/capi selftest#3206
cristina-suteu wants to merge 29 commits into
mainfrom
staging/capi-selftest

Conversation

@cristina-suteu

Copy link
Copy Markdown
Collaborator

Pull Request Description

This PR implements a platform agnostic system test of the CAPI platform drivers.

PR Type

  • Bug fix (change that fixes an issue)
  • New feature (change that adds new functionality)
  • Breaking change (has dependencies in other repos or will cause CI to fail)

PR Checklist

  • I have followed the Coding style guidelines
  • I have complied with the Submission Checklist
  • I have performed a self-review of the changes
  • I have commented my code, at least hard-to-understand parts
  • I have build all projects affected by the changes in this PR
  • I have tested in hardware affected projects, at the relevant boards
  • I have signed off all commits from this PR
  • I have updated the documentation (wiki pages, ReadMe etc), if applies

Voc94 and others added 29 commits July 6, 2026 14:56
- add capi_platform.h with common platform definitions

Signed-off-by: Popa Alexandru Vasile <Alexandruvasile.Popa@analog.com>
  Added PS (XGpioPs) and PL (XGpio) backends, each with its own ops table
  selecting the implementation at init. PS uses global pin IDs with bank-boundary
  validation; PL uses per-channel 32-bit registers. Both support active-low masks,
  port and pin APIs, and soft-fail IRQ connect. Tested on ZedBoard (Zynq-7000)
  with GIC, INTC, and no-IRQ XSA variants & ZCU102(GIC-only).

  Add xilinx_capi_gpio_priv.h defining the internal
  capi_gpio_xilinx_port_handle struct and driver contract shared
  between the PS (XGpioPs) and PL (XGpio) GPIO backends.

Signed-off-by: Popa Alexandru Vasile <Alexandruvasile.Popa@analog.com>
  Add the Xilinx CAPI interrupt-controller backends, covering three
  topologies with two object files and no weak symbols. Exactly one file
  owns the public capi_irq_init() API; linking two roots is a
  duplicate-symbol error by design (one system, one root controller).
  The owner is selected at compile time from XPAR_XSCUGIC_NUM_INSTANCES:

    1. GIC-only   (Zynq/ZynqMP/Versal): link gic.c              extra = NULL
    2. INTC-only  (MicroBlaze):         link intc.c             extra = NULL
    3. Cascade    (PS GIC + PL INTC):   link gic.c + intc.c     extra = &xtra

  In cascade mode gic.c is the root and intc.c builds as a sub-controller
  (exporting only xilinx_capi_irq_intc_subctrl); config->extra points at a
  struct capi_irq_xilinx_extra to hand the root that sub-controller.

  IRQ ids are bit-packed, not range-partitioned: bits [31:16] select the
  controller (CAPI_IRQ_XILINX_CTRL_GIC/INTC) and bits [15:0] are the
  controller-local input. The CAPI_IRQ_XILINX_GIC()/INTC() macros build
  ids and capi_irq_xilinx_ctrl()/_local_id() decode them. A bare id has a
  zero high half, decoding to GIC, which also lets plain INTC input
  numbers work unwrapped on a standalone INTC root.

  - xilinx_capi_irq.h: id encoding, sub-controller (cascade) interface,
    and the capi_irq_init() extra block
  - xilinx_capi_irq_gic.c: GIC root backend (XScuGic wiring, priority and
    trigger config, handler dispatch)
  - xilinx_capi_irq_intc.c: AXI INTC backend, usable as MicroBlaze root or
    as a sub-controller cascaded to a single GIC SPI

Signed-off-by: Popa Alexandru Vasile <Alexandruvasile.Popa@analog.com>
  - xilinx_capi_uart.h: public header; platform-specific config
    (capi_uart_xilinx_config) selecting optional CAPI IRQ connection
  - xilinx_capi_uart_priv.h: private contract for backend sources and
    tests; the capi_uart_xilinx_handle storage, the
    CAPI_UART_HANDLE_XILINX_DEFINE() stack-allocation macro, and the
    per-backend ops tables (selected via config->ops)
  - xilinx_capi_uart_ps.c: PS UART (XUartPs)
  - xilinx_capi_uart_pl_lite.c: AXI UartLite (XUartLite) -> fixed 8N1, no
    per-direction IRQ isolation, so non-default line config and
    set_irq_tx/rx return -ENOTSUP
  - xilinx_capi_uart_pl_ns550.c: AXI UART 16550 (XUartNs550); IER enabled
    only during transfers to avoid a level-triggered interrupt storm,
    asserts OUT2 as the global interrupt gate

  Unsupported flow control, address mode and sticky parity return -ENOTSUP.
  IRQ is wired via capi_irq_connect with soft-fail to polled.

Signed-off-by: Popa Alexandru Vasile <Alexandruvasile.Popa@analog.com>
  Add the Xilinx CAPI SPI driver backends, one ops table per controller
  family selected via config->ops.

  - xilinx_capi_spi.h: shared handle, config and ops declarations
  - xilinx_capi_spi_priv.h: private contract for backend sources and
    tests; the capi_spi_xilinx_handle and async-transfer state, the
    CAPI_SPI_HANDLE_XILINX_DEFINE() stack-allocation macro, and the
    per-backend ops tables
  - xilinx_capi_spi_ps.c: PS SPI (XSpiPs), master mode only, native
    CS0/CS1/CS2 or GPIO chip-select; lsb_first, three_pin_mode, loopback
    and per-transfer delay return -ENOTSUP
  - xilinx_capi_spi_pl.c: AXI Quad SPI (XSpi), master mode only

  Async transfers require use_irq; wired via capi_irq_connect with
  soft-fail to polled. Identifiers are SDT-style base addresses.

Signed-off-by: Popa Alexandru Vasile <Alexandruvasile.Popa@analog.com>
Add the Xilinx CAPI I2C driver backends, one ops table per controller
  family selected via config->ops.

- xilinx_capi_i2c.h: public header; platform config
    (capi_i2c_xilinx_config), including optional AXI IIC timing fields
    (input_clock_hz, thigh/tlow offsets, default bus rate and duty cycle)
  - xilinx_capi_i2c_priv.h: private contract; the capi_i2c_xilinx_handle,
    async-phase tracking, and the per-backend ops tables. Handles use a
    priv pointer (separate CAPI-handle and Xilinx-state allocations)
  - xilinx_capi_i2c_ps.c: PS I2C (XIicPs); master and slave modes,
    7/10-bit addressing, repeated-start via no_stop, polled transfers wait
    for the bus to go idle, status->errno mapping and reset/restore on
    error; duty_cycle returns -ENOTSUP
  - xilinx_capi_i2c_pl.c: AXI IIC (XIic); master and target modes. Bus
    speed is configurable only when the design exposes timing registers:
    set input_clock_hz and configure_bus_speed programs thigh/tlow from
    the requested rate and duty cycle. It returns -ENOTSUP when no input
    clock is set, when the requested rate is too fast for that clock, or
    when the duty cycle rounds a clock phase to zero.
 - Target-role registration is runtime,similar to STM32
   not init-locked: register_target() switches an initialized controller (PS or PL)
   into target mode and unregister_target() restores initiator mode.
   The ISR dispatches on the controller's current role, so a controller
   opened as an initiator can be turned into a target and back. On PL
   this stops the engine to program the response address, then restarts it.

  Async transfers require use_irq; wired via capi_irq_connect with
  soft-fail to polled. Base-address lookup is SDT-style.

Signed-off-by: Popa Alexandru Vasile <Alexandruvasile.Popa@analog.com>
  Add the Xilinx CAPI timer driver backends, one ops table per controller
  family selected via config->ops.

  - xilinx_capi_timer.h: public header; platform config
    (capi_timer_xilinx_config) selecting optional CAPI IRQ connection
  - xilinx_capi_timer_priv.h: private contract; per-channel state, the
    capi_timer_xilinx_handle, the CAPI_TIMER_HANDLE_XILINX_DEFINE()
    stack-allocation macro, and the per-backend ops tables
  - xilinx_capi_timer_ps_ttc.c: PS TTC (XTtcPs); counts up, always rolls
    over, overflow event via the count-overflow mask
  - xilinx_capi_timer_ps_scu.c: SCU timer (XScuTimer); counts down, loads
    max-1 since it fires after load+1 cycles, compare_get returns reg+1
  - xilinx_capi_timer_pl.c: AXI Timer (XTmrCtr); per-channel and global
    callbacks fire independently

  Non-rollover/min-count configs return -ENOTSUP. IRQ wired via
  capi_irq_connect with soft-fail to polled. Base-address lookup is SDT-style.

  Signed-off-by: Popa Alexandru Vasile <Alexandruvasile.Popa@analog.com>
  Add the Xilinx strong implementations of the weak capi_time hooks
  declared in capi/src/capi_time.c -- overridden at link time, no header
  needed.

  - xilinx_capi_time.c: capi_wait_us_impl/capi_wait_ms_impl use the BSP
    usleep() on PS targets and usleep_MB() on MicroBlaze
    (_XPARAMETERS_PS_H_ distinguishes them); capi_uptime_impl reads the
    64-bit global timer via XTime_GetTime()

  Uptime uses the SDT BSP timer interface (xiltimer.h / xtimer_config.h);
  SDT builds are compiled with -DSDT.

Signed-off-by: Popa Alexandru Vasile <Alexandruvasile.Popa@analog.com>
    Add the Xilinx-backed definitions of the CAPI_PLATFORM_IO_* read/write
    macros, mapping them onto the BSP Xil_In / Xil_Out primitives.

    - xilinx_capi_platform.h: header-only, no .c counterpart -- pure macro
      definitions overriding the stubbed defaults in capi/inc/capi_platform.h

Signed-off-by: Popa Alexandru Vasile <Alexandruvasile.Popa@analog.com>
 - xilinx_capi_alloc.c: capi_malloc_impl/capi_free_impl/capi_calloc_impl/
    capi_realloc_impl map straight onto the standard C library
    malloc/free/calloc/realloc. Mirrors the STM32 backend so a Xilinx
    build resolves the capi_alloc symbols to a strong definition instead
    of the weak default.

Signed-off-by: Popa Alexandru Vasile <Alexandruvasile.Popa@analog.com>
  Add a self-test project that exercises CAPI platform drivers and reports
  results over the console UART.

  - test_framework: pass/fail/skip tracking, value/section reporting, and
    whole-run watchdog hooks (test_framework.c/.h)
  - common_data: platform-neutral UART config and the framework output
    transport, a chunked polled UART writer (common_data.c/.h)
  - basic_example: UART transmit/line-config/fifo tests demonstrating
    framework usage (src/examples/basic/basic_example.c)
  - xilinx platform: main.c entry point, parameters.h board mapping, and
    platform_src.mk driver wiring
  - stm32 platform: main.c entry point, parameters.h board mapping, and
    platform_src.mk driver wiring
  - build: Makefile and src.mk build wiring
  - doc: Sphinx stub under doc/sphinx/source/projects/examples

Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
Co-authored-by: Cristina Suteu <cristina.suteu@analog.com>
  Add the capi_loopback example that owns the top-level test registry and
  the test framework lifetime, driven over the console UART.

  - capi_loopback: example_main runs the registered test groups and reports
    a combined pass/fail summary (capi_loopback.c/.mk)
  - test_gpio: GPIO port loopback suite covering direction, raw value
    loopback, error paths and repeated init/deinit (tests/test_gpio.c/.h)
  - common_data: GPIO output/input port configs, gated on GPIO_OUTPUT_OPS so
    the test stays inert until a platform maps GPIO
  - src.mk: build the CAPI GPIO core (capi_gpio.c)

  The GPIO test builds against the CAPI GPIO API and stays inert until a
  platform maps GPIO_OPS, so it lands ahead of the per-platform configs.

Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
  Enable the GPIO loopback test on Xilinx by mapping the PS GPIO (XGpioPs)
  EMIO pins and building the xilinx GPIO backend.

  - parameters.h: GPIO_OUTPUT/INPUT defines for the ZedBoard JA PMOD EMIO
    pair (drive JA2 pin 55, read back JA1 pin 54)
  - platform_src.mk: build xilinx_capi_gpio_ps.c

Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
  Enable the GPIO loopback test on STM32 by mapping the NUCLEO-F767ZI GPIO
  pins and building the stm32 GPIO backend.

  - parameters.h: GPIO_OUTPUT/INPUT defines for the PE0/PF0 loopback pair
    (PE0 output wired to PF0 input)
  - platform_src.mk: build stm32_capi_gpio.c

Signed-off-by: Cristina Suteu <cristina.suteu@analog.com>
Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
  Add the CAPI IRQ controller test to the capi_loopback example.

  - test_irq: IRQ suite covering pre-init rejection, init/deinit lifecycle
    (single owner, double-init -EBUSY), global enable/disable and the
    connect/enable/status/disable path with argument validation; compiles as
    not-configured until a platform defines IRQ_CTRL_IDENTIFIER
    (tests/test_irq.c/.h)
  - capi_loopback: register the IRQ test group
  - src.mk: build the CAPI IRQ core (capi_irq.c)

  How an interrupt source is raised is platform-specific and outside the CAPI
  IRQ contract, so live delivery is left out of the platform-neutral suite.
  The suite deinits the controller while exercising lifecycle, then restores
  it initialized and globally enabled so the IRQ-backed async tests that run
  after it (SPI, timer, I2C) keep working.

Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
  Map the PS GIC as the CAPI IRQ controller so the IRQ test (and every
  IRQ-backed async peripheral) can initialize it via capi_irq_init().

  - parameters.h: IRQ_CTRL_IDENTIFIER (XPAR_XSCUGIC_0_BASEADDR) and the
    xilinx IRQ backend include

Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
  Add the CAPI SPI external-loopback test to the capi_loopback example.

  - test_spi: SPI loopback suite covering basic transfer, async delivery,
    transfer abort, re-init and error paths (tests/test_spi.c/.h)
  - capi_loopback: register the SPI test group
  - common_data: SPI controller/device configs and the IRQ controller
    config, gated on SPI_OPS so the test stays inert until a platform maps SPI
  - src.mk: build the CAPI SPI and IRQ cores (capi_spi.c, capi_irq.c)

Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
  Enable the SPI loopback test on Xilinx by mapping the PS SPI (XSpiPs)
  EMIO controller and building the xilinx SPI backend. SPI async runs over
  the GIC, so main initializes the IRQ controller once at startup.

  - parameters.h: SPI defines for the ZedBoard JC PMOD EMIO loopback
    (MOSI JC2 wired to MISO JC3), GIC IRQ id and controller identifier
  - main.c: initialize the IRQ controller when SPI async (IRQ) is enabled
  - platform_src.mk: build xilinx_capi_spi_ps.c

Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
  Enable the SPI loopback test on STM32 by mapping SPI1 on the NUCLEO-F767ZI
  and building the stm32 SPI and IRQ backends. SPI async runs over the NVIC.

  - parameters.h: SPI1 defines for the PA5/PA6/PA7 loopback (MOSI PA7 wired
    to MISO PA6), NVIC IRQ selection and controller identifier
  - platform_src.mk: build stm32_capi_spi.c and stm32_capi_irq.c

Signed-off-by: Cristina Suteu <cristina.suteu@analog.com>
Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
  Add the CAPI timer test to the capi_loopback example.

  - test_timer: timer suite covering counter movement, count-rate check,
    compare/IRQ delivery and re-init (tests/test_timer.c/.h)
  - capi_loopback: register the timer test group
  - common_data: timer config, gated on TIMER_OPS so the test stays inert
    until a platform maps a timer
  - src.mk: build the CAPI timer core (capi_timer.c)

Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
  Enable the timer test on Xilinx by mapping the PS TTC (XTtcPs) and
  building the TTC backend plus the CAPI time (uptime) hook the test relies
  on. TTC0 sits behind the GIC, so its overflow interrupt is a level-high
  SPI on the same delivery path as the PS SPI/UART.

  - parameters.h: TTC timer defines — base, clock, GIC IRQ id, 16-bit
    counter shape and the rate-check window/tolerance
  - platform_src.mk: build xilinx_capi_timer_ps_ttc.c and the
    xilinx_capi_time.c uptime backend

Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
  Enable the timer test on STM32 by mapping TIM2 on the NUCLEO-F767ZI and
  building the stm32 timer backend. TIM2 is a 32-bit APB1 timer whose input
  clock is auto-detected and whose output is programmed to 1 MHz for 1 us
  resolution; its overflow runs over the NVIC.

  - parameters.h: TIM2 defines — identifier, NVIC IRQ, 32-bit counter shape,
    1 MHz output frequency and the rate-check window/tolerance
  - platform_src.mk: build stm32_capi_timer.c

Signed-off-by: Cristina Suteu <cristina.suteu@analog.com>
Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
  Add the CAPI I2C initiator/target loopback test to the capi_loopback
  example.

  - test_i2c: I2C suite covering initiator/target transfer, async delivery
    and error paths; compiles as not-configured until a platform maps I2C
    (tests/test_i2c.c/.h)
  - capi_loopback: register the I2C test group
  - common_data: I2C initiator and target configs, gated on I2C_OPS and
    I2C_TARGET_OPS so the test stays inert until a platform maps I2C
  - src.mk: build the CAPI I2C core (capi_i2c.c)

Signed-off-by: Cristina Suteu <cristina.suteu@analog.com>
Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
  Enable the I2C initiator/target loopback test on Xilinx by mapping two
  controllers and building both I2C backends. The PL AXI IIC (XIic) is the
  initiator over its fabric IRQ; the PS I2C (XIicPs) answers as the target
  behind the GIC. Wire the two buses together (SCL<->SCL, SDA<->SDA) with
  pull-ups.

  - parameters.h: I2C initiator (PL AXI IIC) and target (PS I2C) defines —
    base addresses, IRQ ids and the shared target address; the platform
    hooks are no-ops since the GIC singleton routes interrupts and the BSP
    handles clocking
  - platform_src.mk: build xilinx_capi_i2c_pl.c and xilinx_capi_i2c_ps.c

Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
  Enable the I2C initiator/target loopback test on STM32 by mapping I2C1 as
  initiator and I2C2 as target on the NUCLEO-F767ZI, wired PB6/PB9 <->
  PB10/PB11.

  CubeMX only generates setup for I2C1, so i2c_platform_init brings up I2C2's
  clock, pins and NVIC and installs the IRQ vectors that dispatch to
  capi_i2c_isr; the test calls I2C_PLATFORM_SET_TARGET() after init so those
  vectors reach the target controller handle.

  - parameters.h: I2C1/I2C2 defines and the platform-hook declarations
  - i2c_platform_init.c: I2C2 clock/GPIO/NVIC bring-up and IRQ dispatch
  - platform_src.mk: build stm32_capi_i2c.c and i2c_platform_init.c

Signed-off-by: Cristina Suteu <cristina.suteu@analog.com>
Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
  Add the CAPI memory-to-memory DMA test to the capi_loopback example.

  - test_dma: DMA suite covering mem-to-mem transfer, config/xfer paths,
    re-init and error paths; compiles as not-configured until a platform
    maps DMA (tests/test_dma.c/.h)
  - capi_loopback: register the DMA test group
  - common_data: DMA config and transfer extra, gated on DMA_OPS so the test
    stays inert until a platform maps DMA
  - src.mk: build the CAPI DMA core (capi_dma.c)

Signed-off-by: Cristina Suteu <cristina.suteu@analog.com>
Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
  Enable the memory-to-memory DMA test on STM32 by mapping DMA2 on the
  NUCLEO-F767ZI and building the stm32 DMA backend. Only DMA2 supports
  mem-to-mem; stream 0 / channel 0 runs in polling mode (no peripheral
  trigger or interrupt needed).

  - parameters.h: DMA2 stream/channel defines, mem-to-mem transfer extra and
    the DMA2 clock-enable platform hook
  - platform_src.mk: build stm32_capi_dma.c

Signed-off-by: Cristina Suteu <cristina.suteu@analog.com>
Signed-off-by: Alexandru Vasile Popa <Alexandruvasile.Popa@analog.com>
added uart extra config needed for stm32 test

Signed-off-by: Cristina Suteu <cristina.suteu@analog.com>
print the current section being tested before running tests
for better visibility

Signed-off-by: Cristina Suteu <cristina.suteu@analog.com>
@adi-ramonimbao

adi-ramonimbao commented Jul 16, 2026

Copy link
Copy Markdown

Hi. I can't get the GPIO port loopback test to pass on the MAX32657. Since there's only one GPIO port, I don't know how to set it up such that P0.0 and P0.1 are the pin pair to be tested.

I've written a GPIO pin loopback test that should not need any additional changes to the STM32 and Xilinx platforms:
https://github.com/adi-ramonimbao/no-OS/blob/staging/capi-selftest-max32657/projects/capi_selftest/src/examples/capi_loopback/tests/test_gpio.c#L102-L193

There are a few additions in common_data.c and common_data.h as well:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants