device_mmio: Introduce DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME
Currently the device MMIO APIs is only able to map single DT-defined regions and also the _NAMED variant is assuming that each DT-defined device has only one single region to map. This is a limitation and a problem when in the DT are defined devices with multiple regions that need to be mapped. This patch is trying to overcome this limitation by introducing the DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME macro that leveraged the 'reg-names' DT property to map multiple regions defined by a single device. So for example in the DT we can have a device like: driver@c4000000 { reg = <0xc4000000 0x1000>, <0xc4001000 0x1000>; reg-names = "region0", "region1"; }; and then we can use DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME doing: struct driver_config config = { DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(region0, DT_DRV_INST(0)), DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(region1, DT_DRV_INST(0)), }; Signed-off-by: Carlo Caione <ccaione@baylibre.com>
This commit is contained in:
parent
9a4c3f1afa
commit
b6a3d598f3
5 changed files with 194 additions and 1 deletions
|
@ -529,6 +529,37 @@ For example:
|
|||
...
|
||||
}
|
||||
|
||||
Device Model Drivers with multiple MMIO regions in the same DT node
|
||||
===================================================================
|
||||
|
||||
Some drivers may have multiple MMIO regions defined into the same DT device
|
||||
node using the ``reg-names`` property to differentiate them, for example:
|
||||
|
||||
.. code-block:: devicetree
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
a-driver@40000000 {
|
||||
reg = <0x40000000 0x1000>,
|
||||
<0x40001000 0x1000>;
|
||||
reg-names = "corge", "grault";
|
||||
};
|
||||
};
|
||||
|
||||
This can be managed as seen in the previous section but this time using the
|
||||
``DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME`` macro instead. So the only difference
|
||||
would be in the driver config struct:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
const static struct my_driver_config my_driver_config_0 = {
|
||||
...
|
||||
DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(corge, DT_DRV_INST(...)),
|
||||
DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(grault, DT_DRV_INST(...)),
|
||||
...
|
||||
}
|
||||
|
||||
Drivers that do not use Zephyr Device Model
|
||||
===========================================
|
||||
|
||||
|
|
|
@ -62,6 +62,12 @@ struct z_device_mmio_rom {
|
|||
.size = DT_REG_SIZE(node_id) \
|
||||
}
|
||||
|
||||
#define Z_DEVICE_MMIO_NAMED_ROM_INITIALIZER(name, node_id) \
|
||||
{ \
|
||||
.phys_addr = DT_REG_ADDR_BY_NAME(node_id, name), \
|
||||
.size = DT_REG_SIZE_BY_NAME(node_id, name) \
|
||||
}
|
||||
|
||||
/**
|
||||
* Set linear address for device MMIO access
|
||||
*
|
||||
|
@ -112,6 +118,12 @@ struct z_device_mmio_rom {
|
|||
{ \
|
||||
.addr = DT_REG_ADDR(node_id) \
|
||||
}
|
||||
|
||||
#define Z_DEVICE_MMIO_NAMED_ROM_INITIALIZER(name, node_id) \
|
||||
{ \
|
||||
.addr = DT_REG_ADDR_BY_NAME(node_id, name) \
|
||||
}
|
||||
|
||||
#endif /* DEVICE_MMIO_IS_IN_RAM */
|
||||
#endif /* !_ASMLANGUAGE */
|
||||
/** @} */
|
||||
|
@ -435,6 +447,49 @@ struct z_device_mmio_rom {
|
|||
#define DEVICE_MMIO_NAMED_ROM_INIT(name, node_id) \
|
||||
.name = Z_DEVICE_MMIO_ROM_INITIALIZER(node_id)
|
||||
|
||||
/**
|
||||
* @def DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(name, node_id)
|
||||
*
|
||||
* @brief Initialize a named DEVICE_MMIO_NAMED_ROM member using a named DT
|
||||
* reg property.
|
||||
*
|
||||
* Same as @ref DEVICE_MMIO_NAMED_ROM_INIT but the size and address are taken
|
||||
* from a named DT reg property.
|
||||
*
|
||||
* Example for an instance of a driver belonging to the "foo" subsystem
|
||||
* that will have two DT-defined regions named 'chip' and 'dale':
|
||||
*
|
||||
* @code{.dts}
|
||||
*
|
||||
* foo@E5000000 {
|
||||
* reg = <0xE5000000 0x1000>, <0xE6000000 0x1000>;
|
||||
* reg-names = "chip", "dale";
|
||||
* ...
|
||||
* };
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
* @code{.c}
|
||||
*
|
||||
* struct foo_config my_config = {
|
||||
* bar = 7;
|
||||
* DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(chip, DT_DRV_INST(...));
|
||||
* DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(dale, DT_DRV_INST(...));
|
||||
* baz = 2;
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
* @see DEVICE_MMIO_NAMED_ROM_INIT()
|
||||
*
|
||||
* @param name Member name within config for the MMIO region and name of the
|
||||
* reg property in the DT
|
||||
* @param node_id DTS node identifier
|
||||
*/
|
||||
#define DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(name, node_id) \
|
||||
.name = Z_DEVICE_MMIO_NAMED_ROM_INITIALIZER(name, node_id)
|
||||
|
||||
/**
|
||||
* @def DEVICE_MMIO_NAMED_MAP(dev, name, flags)
|
||||
*
|
||||
|
|
|
@ -42,4 +42,13 @@
|
|||
reg = <0xE4000000 0x2000>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
fakedriver_multireg@E5000000 {
|
||||
compatible = "fakedriver_multireg";
|
||||
reg = <0xE5000000 0x1000>,
|
||||
<0xE6000000 0x1000>;
|
||||
reg-names = "chip",
|
||||
"dale";
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
|
|
@ -24,6 +24,7 @@ extern void test_mmio_multiple(void);
|
|||
extern void test_mmio_toplevel(void);
|
||||
extern void test_mmio_single(void);
|
||||
extern void test_mmio_device_map(void);
|
||||
extern void test_mmio_multireg(void);
|
||||
|
||||
/**
|
||||
* @brief Test cases to verify device objects
|
||||
|
@ -364,6 +365,7 @@ void test_main(void)
|
|||
ztest_unit_test(test_mmio_single),
|
||||
ztest_unit_test(test_mmio_multiple),
|
||||
ztest_unit_test(test_mmio_toplevel),
|
||||
ztest_unit_test(test_mmio_device_map));
|
||||
ztest_unit_test(test_mmio_device_map),
|
||||
ztest_unit_test(test_mmio_multireg));
|
||||
ztest_run_test_suite(device);
|
||||
}
|
||||
|
|
96
tests/kernel/device/src/mmio_multireg.c
Normal file
96
tests/kernel/device/src/mmio_multireg.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Intel Corporation
|
||||
* Copyright (c) 2022 Carlo Caione <ccaione@baylibre.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <ztest.h>
|
||||
#include <zephyr/device.h>
|
||||
|
||||
#define DT_DRV_COMPAT fakedriver_multireg
|
||||
|
||||
/*
|
||||
* Driver with multiple MMIO regions to manage defined into DT
|
||||
*/
|
||||
|
||||
struct foo_multireg_dev_data {
|
||||
int baz;
|
||||
|
||||
DEVICE_MMIO_NAMED_RAM(chip);
|
||||
DEVICE_MMIO_NAMED_RAM(dale);
|
||||
};
|
||||
|
||||
struct foo_multireg_dev_data foo_multireg_data;
|
||||
|
||||
struct foo_multireg_config_info {
|
||||
DEVICE_MMIO_NAMED_ROM(chip);
|
||||
DEVICE_MMIO_NAMED_ROM(dale);
|
||||
};
|
||||
|
||||
const struct foo_multireg_config_info foo_multireg_config = {
|
||||
DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(chip, DT_DRV_INST(0)),
|
||||
DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(dale, DT_DRV_INST(0))
|
||||
};
|
||||
|
||||
#define DEV_DATA(dev) ((struct foo_multireg_dev_data *)((dev)->data))
|
||||
#define DEV_CFG(dev) ((struct foo_multireg_config_info *)((dev)->config))
|
||||
|
||||
int foo_multireg_init(const struct device *dev)
|
||||
{
|
||||
DEVICE_MMIO_NAMED_MAP(dev, chip, K_MEM_CACHE_NONE);
|
||||
DEVICE_MMIO_NAMED_MAP(dev, dale, K_MEM_CACHE_NONE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEVICE_DEFINE(foo_multireg, "foo_multireg", foo_multireg_init, NULL,
|
||||
&foo_multireg_data, &foo_multireg_config,
|
||||
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
|
||||
(void *)0xDEADBEEF);
|
||||
/**
|
||||
* @brief Test DEVICE_MMIO_NAMED_* macros
|
||||
*
|
||||
* This is the same as the @ref test_mmio_multiple test but in this test the
|
||||
* memory regions are created by the named DT property 'reg'.
|
||||
*
|
||||
* @see test_mmio_multiple
|
||||
*
|
||||
* @ingroup kernel_device_tests
|
||||
*/
|
||||
void test_mmio_multireg(void)
|
||||
{
|
||||
const struct device *dev = device_get_binding("foo_multireg");
|
||||
mm_reg_t regs_chip, regs_dale;
|
||||
const struct z_device_mmio_rom *rom_chip, *rom_dale;
|
||||
|
||||
zassert_not_null(dev, "null foo_multireg");
|
||||
|
||||
regs_chip = DEVICE_MMIO_NAMED_GET(dev, chip);
|
||||
regs_dale = DEVICE_MMIO_NAMED_GET(dev, dale);
|
||||
rom_chip = DEVICE_MMIO_NAMED_ROM_PTR(dev, chip);
|
||||
rom_dale = DEVICE_MMIO_NAMED_ROM_PTR(dev, dale);
|
||||
|
||||
zassert_not_equal(regs_chip, 0, "bad regs_chip");
|
||||
zassert_not_equal(regs_dale, 0, "bad regs_dale");
|
||||
|
||||
#ifdef DEVICE_MMIO_IS_IN_RAM
|
||||
zassert_equal(rom_chip->phys_addr, DT_INST_REG_ADDR_BY_NAME(0, chip),
|
||||
"bad phys_addr (chip)");
|
||||
zassert_equal(rom_chip->size, DT_INST_REG_SIZE_BY_NAME(0, chip),
|
||||
"bad size (chip)");
|
||||
zassert_equal(rom_dale->phys_addr, DT_INST_REG_ADDR_BY_NAME(0, dale),
|
||||
"bad phys_addr (dale)");
|
||||
zassert_equal(rom_dale->size, DT_INST_REG_SIZE_BY_NAME(0, dale),
|
||||
"bad size (dale)");
|
||||
#else
|
||||
zassert_equal(rom_chip->addr, DT_INST_REG_ADDR_BY_NAME(0, chip),
|
||||
"bad addr (chip)");
|
||||
zassert_equal(regs_chip, rom_chip->addr, "bad regs (chip)");
|
||||
zassert_equal(rom_dale->addr, DT_INST_REG_ADDR_BY_NAME(0, dale),
|
||||
"bad addr (dale)");
|
||||
zassert_equal(regs_dale, rom_dale->addr, "bad regs (dale)");
|
||||
zassert_equal(sizeof(struct foo_multireg_dev_data), sizeof(int),
|
||||
"too big foo_multireg_dev_data");
|
||||
#endif
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue