Jungo WinDriver  
Official Documentation
Chapter 18: SoCs and Platform Devices

This chapter covers the following topics:

  • Understanding platform devices
  • Defining a device tree node to enable integration with WinDriver
  • Exploring WinDriver APIs for platform devices, along with corresponding alternatives to PCI-based APIs
  • Developing portable drivers that support both PCI and SoC platforms using DriverWizard

ℹ️ Note

This chapter is applicable to Linux only, specifically targeting SoC-based architectures.

18.1. Overview

A System-on-a-Chip (SoC) integrates all the primary components of a computer (such as the CPU, memory controllers, and peripheral interfaces) into a single integrated circuit. Unlike traditional PC architectures (e.g., x86) where components like the GPU or Network Controller reside on a separate bus like PCI, SoC components are interconnected via high-speed internal buses (such as ARM’s AMBA AXI).

18.1.1. Platform Devices

In the Linux kernel, devices are typically categorized by how they are discovered:

  • Discoverable Devices: Peripherals on buses like PCI or USB can be identified by the OS at runtime through hardware registers (Vendor/Device IDs).
  • Platform Devices: These are "non-discoverable" devices. The kernel cannot "scan" for them. Instead, their presence and memory-mapped I/O (MMIO) addresses must be explicitly defined. This is typically handled by the Device Tree (DT) or ACPI tables.

18.1.2. Architecture-Specific Integration

Modern SoCs often include:

  • IP Cores: Pre-designed logic blocks (e.g., Ethernet, I2C, SPI) integrated into the silicon.
  • Programmable Logic (FPGA): In devices like the Xilinx Zynq or Altera Agilex, custom hardware logic is mapped directly into the CPU's memory space, appearing to the OS as a platform device.
  • DMA Engines: Integrated controllers that allow platform devices to move data directly to system RAM without taxing the CPU.

By using WinDriver in this environment, you can access the memory-mapped registers and interrupt lines of these integrated components directly from user space, bypassing the complexity of writing kernel modules for every unique SoC peripheral.

18.2. WinDriver APIs for Platform Devices

WinDriver provides high-level APIs specifically designed for SoC-based platform devices. While many core WinDriver functions are universal, specific APIs exist for scanning and opening platform devices based on the definitions provided in the system Device Tree.

18.2.1. Platform-Specific vs. Universal APIs

For tasks unique to SoC architectures, such as finding a device by its name in the Device Tree, WinDriver uses specialized Platform Device APIs. For general hardware access (I/O, interrupts, DMA), the standard High-Level APIs are used for both PCI and Platform devices.

18.2.1.1. Specialized Platform Functions

These functions are used during the initialization phase to identify and bind to your SoC hardware:

18.2.1.2. Universal High-Level APIs

Once a device handle (WDC_DEVICE_HANDLE) is obtained via WDC_PlatformDeviceOpen(), you use the same high-level functions used for PCI Express to perform hardware operations:

Function Category Universal High-Level API (PCI & Platform)
Read/Write WDC_ReadAddrXXX(), WDC_WriteAddrXXX(), WDC_ReadAddrBlock()
Interrupts WDC_IntEnable(), WDC_IntDisable(), WDC_IntIsEnabled()
DMA WDC_DMAContigBufLock(), WDC_DMASGBufLock(), WDC_DMABufUnlock()
Cleanup WDC_DeviceClose() (unifies PCI, ISA, and Platform closing)

18.2.2. Accessing SoC Registers

Because SoC peripherals are memory-mapped, you can access them directly using the same methods described for PCI cards. After calling WDC_PlatformDeviceOpen(), the physical address defined in your Device Tree reg property is mapped to a user-mode virtual address. You can then use the WDC_ReadAddr / WDC_WriteAddr suite of functions to communicate with your hardware.

18.3. Integrating Your SoC Hardware with WinDriver

To enable WinDriver to manage your custom SoC platform device, you must define a node in your system's Device Tree (DTS). WinDriver will automatically detect this node, bind to the device, and allow you to begin SoC driver development immediately.

18.3.1. Device Tree Template

Copy the following structure into your DTS file to define your peripheral, replacing the placeholders with your hardware-specific values:

<DEVICE_NAME>@<BASE_ADDRESS> {
/* --- Mandatory Fields --- */
compatible = "windriver,platform-device";
reg = <0x<BASE_ADDRESS> 0x<SIZE>>;
status = "okay";
/* --- Interrupt Configuration (Optional) --- */
/* Define these ONLY if your hardware generates interrupt signals */
interrupt-parent = <&<YOUR_INTERRUPT_CONTROLLER_LABEL>>;
interrupts = < <INTERRUPT_SPECIFIER_VALUES> >;
interrupt-names = "irq_name";
};

18.3.2. Register Range

The reg property defines the physical memory space occupied by your device:

  • Base Address: The physical starting address of your peripheral.
  • Size: The address span (in bytes) of your device's registers.

Example: For a device located at 0x40000000 with a 4KB range: reg = <0x40000000 0x1000>;

18.3.3. Interrupt Parent

The interrupt-parent property specifies which hardware component handles the interrupt signal. Locate the label of your system's interrupt controller (e.g., &intc, &gic, or a GPIO bank like &gpio0) and reference it in this field.

18.3.4. Interrupt Specifier

The format of the interrupts field is determined by your interrupt parent. To fill this correctly:

  1. Locate your interrupt controller’s node in the DTS.
  2. Check the #interrupt-cells value.
  3. Provide the corresponding number of parameters:
    • If 3 cells: Commonly used by ARM GIC (Format: <Type ID Flags>).
    • If 2 cells: Common for GPIO-based interrupts (Format: <ID Flags>).

ℹ️ Note

If your device does not use interrupts, you can safely omit the interrupt-parent, interrupts, and interrupt-names fields.

18.3.5. The Status property

Ensure the status property is set to "okay". Setting this to "disabled" will prevent the Linux kernel from probing the device and WinDriver from detecting it.

18.4. Installing WinDriver on SoCs (ARM64)

To install WinDriver for SoC architectures, follow the standard installation procedure detailed in 3.2.2.3. Installing WinDriver on ARM/ARM64 systems.

When executing the wd_arm64_install.sh script, ensure you select the ARM64 SoC Platforms option when prompted to configure the driver for your specific hardware environment.

18.5. Developing a driver compatible with both PCI and SoC

18.5.1. Software Modifications

To maintain a portable codebase that can toggle between PCI and SoC architectures with minimal changes, use the following API alternatives:

PCI API SoC (Platform) API
WDC_PciScanDevices() WDC_PlatformScanDevices()
WDC_PciGetDeviceInfo() WDC_PlatformGetDeviceInfo()
WDC_PciDeviceOpen() WDC_PlatformDeviceOpen()

18.5.1.1. Unified Function Alternatives

Alternatively, WinDriver provides unified functions that can be used for both PCI and SoC platforms. These allow you to maintain a more consistent code structure by simply updating the function arguments to match your hardware instead of switching to an entirely different function set.

18.5.1.2. Compilation Requirements

To transition your driver from PCI to the SoC Platform, you must update your function calls to the corresponding Platform arguments and include the PLATFORM_API definition in your build configuration.

In CMakeLists.txt:

add_compile_definitions(PLATFORM_API)

In Makefile:

CFLAGS += -DPLATFORM_API

18.5.2. Hardware Configurations

If your hardware utilizes Programmable Logic (FPGA) with an IP core compatible with both PCI and Hard Processor Systems (HPS):

  1. Reconnect the IP: Disconnect the IP core from the PCI Express interface and bridge it to the SoC's hard processor (e.g., via an AXI interconnect).
  2. Address Mapping: Assign a specific base address to the IP core within the processor's memory map. This allows the SoC to access the hardware registers directly via memory-mapped I/O (MMIO).

18.6. Developing Platform Device Drivers Using DriverWizard

18.6.1. Driver for a Platform Device

For detailed information on using DriverWizard, see 6.2. DriverWizard Walkthrough.

18.6.1.1. Choose your platform device

When you open DriverWizard, select your platform device from the list of available devices. If the device has not yet been added to the DTS, you can generate code for a virtual platform device by selecting Platform Virtual Device.

18.6.1.2. Diagnose your device

After selecting the device, diagnose it in the same manner described in 6.2.6. Diagnose your device (PCI).

18.6.1.3. Generate your driver

After you have completed the diagnostics and verified that the device operates according to your requirements, you can generate the driver code. Follow the instructions in 6.2.9.1. Samples Or Code Generation to generate code for your platform device.

The generated code will already use the appropriate WinDriver APIs for platform devices, and the generated CMakeLists.txt file or Makefile will already include the definition required for the Platform Device API.

18.6.2. Driver Compatible with Both Platform and PCI Devices

When generating code for either a platform device or a PCI device, DriverWizard displays an Additional Options section. In this section, you can select the following checkbox: Generate application compatible with both PCI and Platform devices

When this option is selected, the generated code includes all adjustments required for compatibility with both PCI and Platform devices. In addition, the generated project includes two build targets, so compiling the code produces two binaries: one for PCI and one for the platform device.