blob: 5d58a6bf15b8f9e0048c35f58cff0e9f6265bc95 [file] [log] [blame] [view]
# Platform Bus
## Introduction
The platform bus manages drivers for devices on SOC-based platforms.
The platform bus is a driver itself (located at
[system/dev/bus/platform](../../system/dev/bus/platform))
and is started automatically by the device manager on platforms that need it.
Currently the platform bus is used on all arm64 platforms.
It is not used on x86 platforms, since ACPI performs a similar role on x86.
On platforms that use it, the platform bus is represented in the device tree as `/sys`.
The platform bus serves the following purposes:
* Creating devices for binding the drivers needed for a particular platform.
* Abstracting away the platform specific details for drivers, such as MMIO addresses,
IRQ and GPIO numbers, etc. so a single driver for a particular hardware device or IP
can be used across multiple platforms.
* Sandboxing, so drivers can access the MMIO ranges, IRQs, GPIOs, I2C addresses, etc.
that they need, but nothing else.
## Initialization
The platform bus driver is a generic driver that contains no specific information about the
platform it is running on.
To provide the platform specific logic for the platform bus, it loads a platform specific
helper driver called the "board driver".
When Zircon boots, the `vid`, `pid` and `board_name` are read from the `BOOTDATA_PLATFORM_ID`
section in the bootdata. This is passed to the Platform Bus driver via the device argument list.
The Platform Bus then adds a device with protocol `ZX_PROTOCOL_PLATFORM_BUS` with the
`BIND_PLATFORM_DEV_VID` and `BIND_PLATFORM_DEV_PID` binding variables set to the vid and did
from the bootdata information. The board driver then binds to this device.
The board driver uses the `ZX_PROTOCOL_PLATFORM_BUS` protocol
(see [system/ulib/ddk/include/ddk/protocol/platform-bus.h](../../system/ulib/ddk/include/ddk/protocol/platform-bus.h))
to communicate with the platform bus driver.
After the board driver initializes itself, it calls `pbus_set_interface()` to register itself
with the platform bus.
This tells the platform bus that the board driver is ready to go, and provides an interface
the platform bus driver can use to communicate with the board driver.
## Platform Devices
After the board driver calls `pbus_set_interface()` to register itself,
it will then typically call `pbus_device_add()` one or more times to create devices
for platform device drivers to bind to. Platform device drivers use the `ZX_PROTOCOL_PLATFORM_DEV` protocol
(see [system/ulib/ddk/include/ddk/protocol/platform-device.h](../../system/ulib/ddk/include/ddk/protocol/platform-device.h))
to communicate with the platform bus.
The platform device protocol is used by platform device drivers to access the resources they need
to function.
To allow development of platform independent drivers, these resources are accessed via device
specific index rather than an a physical address or ID in the global name space.
For example, if a driver needs two IRQs, they will be index zero and one rather than the actual IRQ
numbers on the platform.
Similarly, MMIO ranges are accessed via an index rather than the actual physical address.
This allows us to write drivers that work across multiple platforms, where the basic functionality
of the hardware is the same but details like MMIO addresses and IRQ and GPIO numbers may be
different. The mapping from the indices used by the platform devices and the actual physical values
is provided by the board driver.
Platform device drivers use `pdev_map_mmio()` to map MMIO regions and `pdev_map_interrupt()`
to get interrupt handles for their IRQs. The platform device protocol also provides
`pdev_alloc_contig_vmo()` and `pdev_map_contig_vmo()` to create contiguous VMOs for hardware that
requires contiguous DMA buffers. (It is strongly encouraged to use regular non-contiguous VMOs
whenever possible instead). Finally, the platform device protocol includes `pdev_vmo_buffer_t`,
which is a helper to make it easy to work with VMOs for MMIO ranges and contiguous DMA regions.
## Platform Bus Protocols
In addition to the `ZX_PROTOCOL_PLATFORM_DEV` platform device protocol, the platform bus can provide
additional protocols to platform device drivers. These protocols are also accessed via the DDK
`device_get_protocol` API. For example, the platform bus can provide the `ZX_PROTOCOL_GPIO`
protocol for GPIOs and `ZX_PROTOCOL_I2C` for devices on an I2C bus.
The implementation of these protocols live in the board driver.
The board driver provides this via the `pbus_interface_get_protocol` call in the interface
that the board driver registers with the platform bus.
For these protocols, the resources are also accessed via an abstract index rather than raw
value to insulate the platform device driver from the specifics of the platform.