Skip to content

Commit

Permalink
doc: add device MMIO details
Browse files Browse the repository at this point in the history
Add some overview documentation on how to use this header.

Signed-off-by: Andrew Boie <[email protected]>
  • Loading branch information
Andrew Boie authored and carlescufi committed Jul 17, 2020
1 parent aec607c commit e33fc71
Showing 1 changed file with 178 additions and 2 deletions.
180 changes: 178 additions & 2 deletions doc/reference/drivers/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ with a different interrupt line. In ``drivers/subsystem/subsystem_my_driver.h``:
typedef void (*my_driver_config_irq_t)(struct device *device);
struct my_driver_config {
uint32_t base_addr;
DEVICE_MMIO_ROM;
my_driver_config_irq_t config_func;
};
Expand All @@ -302,6 +302,8 @@ In the implementation of the common init function:
{
const struct my_driver_config *config = device->config_info;
DEVICE_MMIO_MAP(device, K_MEM_CACHE_NONE);
/* Do other initialization stuff */
...
Expand All @@ -325,7 +327,7 @@ Then when the particular instance is declared:
}
const static struct my_driver_config my_driver_config_0 = {
.base_addr = MY_DRIVER_0_BASE_ADDR,
DEVICE_MMIO_ROM_INIT(0),
.config_func = my_driver_config_irq_0
}
Expand Down Expand Up @@ -421,6 +423,180 @@ returned on failure. See
https://github.com/zephyrproject-rtos/zephyr/wiki/Naming-Conventions#return-codes
for details about this.

Memory Mapping
**************

On some systems, the linear address of peripheral memory-mapped I/O (MMIO)
regions cannot be known at build time:

- The I/O ranges must be probed at runtime from the bus, such as with
PCI express
- A memory management unit (MMU) is active, and the physical address of
the MMIO range must be mapped into the page tables at some virtual
memory location determined by the kernel.

These systems must maintain storage for the MMIO range within RAM and
establish the mapping within the driver's init function. Other systems
do not care about this and can use MMIO physical addresses directly from
DTS and do not need any RAM-based storage for it.

For drivers that may need to deal with this situation, a set of
APIs under the DEVICE_MMIO scope are defined, along with a mapping function
:cpp:func:`device_map()`.

Device Model Drivers with one MMIO region
=========================================

The simplest case is for drivers which need to maintain one MMIO region.
These drivers will need to use the ``DEVICE_MMIO_ROM`` and
``DEVICE_MMIO_RAM`` macros in the definitions for their ``config_info``
and ``driver_data`` structures, with initialization of the ``config_info``
from DTS using ``DEVICE_MMIO_ROM_INIT``. A call to ``DEVICE_MMIO_MAP()``
is made within the init function:

.. code-block:: C
struct my_driver_config {
DEVICE_MMIO_ROM; /* Must be first */
...
}
struct my_driver_dev_data {
DEVICE_MMIO_RAM; /* Must be first */
...
}
const static struct my_driver_config my_driver_config_0 = {
DEVICE_MMIO_ROM_INIT(DT_INST(...)),
...
}
int my_driver_init(struct device *device)
{
...
DEVICE_MMIO_MAP(device, K_MEM_CACHE_NONE);
...
}
int my_driver_some_function(struct device *device)
{
...
/* Write some data to the MMIO region */
sys_write32(DEVICE_MMIO_GET(device), 0xDEADBEEF);
...
}
The particular expansion of these macros depends on configuration. On
a device with no MMU or PCI-e, ``DEVICE_MMIO_MAP`` and
``DEVICE_MMIO_RAM`` expand to nothing.

Device Model Drivers with multiple MMIO regions
===============================================

Some drivers may have multiple MMIO regions. In addition, some drivers
may already be implementing a form of inheritance whice requires some other
data to be placed first in the ``config_info`` and ``driver_data``
structures.

This can be managed with the ``DEVICE_MMIO_NAMED`` variant macros. These
require that ``DEV_CFG()`` and ``DEV_DATA()`` macros be defined to obtain
a properly typed pointer to the driver's config_info or dev_data structs.
For example:

.. code-block:: C
struct my_driver_config {
...
DEVICE_MMIO_NAMED_ROM(courge);
DEVICE_MMIO_NAMED_ROM(grault);
...
}
struct my_driver_dev_data {
...
DEVICE_MMIO_NAMED_RAM(courge);
DEVICE_MMIO_NAMED_RAM(grault);
...
}
#define DEV_CFG(_dev) \
((const struct my_driver_config *)((_dev)->config_info))
#define DEV_DATA(_dev) \
((struct my_driver_dev_data *)((_dev)->driver_data))
const static struct my_driver_config my_driver_config_0 = {
...
DEVICE_MMIO_NAMED_ROM_INIT(courge, DT_INST(...)),
DEVICE_MMIO_NAMED_ROM_INIT(grault, DT_INST(...)),
...
}
int my_driver_init(struct device *device)
{
...
DEVICE_MMIO_NAMED_MAP(device, courge, K_MEM_CACHE_NONE);
DEVICE_MMIO_NAMED_MAP(device, grault, K_MEM_CACHE_NONE);
...
}
int my_driver_some_function(struct device *device)
{
...
/* Write some data to the MMIO regions */
sys_write32(DEVICE_MMIO_GET(device, grault), 0xDEADBEEF);
sys_write32(DEVICE_MMIO_GET(device, courge), 0xF0CCAC1A);
...
}
Drivers that do not use Zephyr Device Model
===========================================

Some drivers or driver-like code may not user Zephyr's device model,
and alternative storage must be arranged for the MMIO data. An
example of this are timer drivers, or interrupt controller code.

This can be managed with the ``DEVICE_MMIO_TOPLEVEL`` set of macros,
for example:

.. code-block:: C
DEVICE_MMIO_TOPLEVEL_STATIC(my_regs, DT_INST(..));
void some_init_code(...)
{
...
DEVICE_MMIO_TOPLEVEL_MAP(my_regs, K_MEM_CACHE_NONE);
...
}
void some_function(...)
...
sys_write32(DEVICE_MMIO_TOPLEVEL_GET(my_regs), 0xDEADBEEF);
...
}
Drivers that do not use DTS
===========================

Some drivers may not obtain the MMIO physical address from DTS, such as
is the case with PCI-E. In this case the :cpp:func:`device_map()` function
may be used directly:

.. code-block:: C
void some_init_code(...)
{
...
uintptr_t phys_addr = pcie_get_mbar(...);
size_t size = ...
device_map(DEVICE_MMIO_RAM_PTR(dev), phys_addr, size, K_MEM_CACHE_NONE);
...
}
For these cases, DEVICE_MMIO_ROM directives may be omitted.

API Reference
**************

Expand Down

0 comments on commit e33fc71

Please sign in to comment.