[U-Boot] [PATCH 0/3] dm: add dev_get_reg() for getting device node's reg

Stephen Warren
2016-01-06T19:14:25Z

On 01/05/2016 05:24 PM, Simon Glass wrote:...
> I'm not super-keen on dev_get_reg() as it adds confusion - why is one
> reg dealt with differently from another. Perhaps just a different
> name, like dev_get_bus_addr()?
>
> Re Linux, can someone trace through the of_address_to_resource() call
> and see what it actually does? It seems to call of_translate_address()
> but presumably does not suffer from this problem. So maybe I am
> missing something. The S3C I2C driver calls platform_get_resource()
> which is presumably set up by a call to of_address_to_resource()?

At least in ARM DT land, most MMIO devices are "platform devices". There
are also e.g. PCIe devices, but they're enumerated via HW protocols, not
by parsing DT.

Construction of a platform device works as follows in the Linux source:

For each node that's found by scanning the DT, a struct platform_device
is created to represent it, in drivers/of/platform.c of_device_alloc().
Note that this scanning process is only performed on DT nodes known to
represent MMIO buses; recursion into child nodes is explicitly performed
by drivers for particular nodes, and takes a different path for nodes
representing non-MMIO buses, as described later, since the node's driver
will be different. This scanning process is core code that executes
before the kernel has any idea re: which type of device the child nodes
represent, or which driver will manage them. This struct contains the
values of a number of core resource types that are represented in DT,
such as addresses, IRQs, etc. The address values are filled in via the
following call stack:

drivers/of/platform.c of_device_alloc()

->

drivers/of/address.c of_address_to_resource()

->

drivers/of/address.c of_get_address()

[reads the reg property, picks out a single index in it, performs BE->LE
conversion]

then unconditionally calls the following on the address:

drivers/of/address.c __of_address_to_resource()

[translates the address to the CPU address space, then writes the result
into the supplied pointer, which the caller has set up to point into a
struct resource associated with the struct platform_device]

->

drivers/of/address.c of_translate_address()

->

drivers/of/address.c __of_translate_address()

This is essentially exactly identical to U-Boot's
__of_translate_address(), modulo a few printf()/debug() differences, and
a few more of_node_get/put() calls in order to support dynamic
modifications to the DT.

The driver for the a DT node is responsible for enumerating (or
triggering enumeration of) any child nodes. For a node known to
represent an MMIO bus (e.g. simple-bus), the algorithm above will simply
be applied recursively. For a node that represents some kind of non-MMIO
bus controller/host, custom (bus-type-specific) code is typically
applied. In many cases, this custom code will parse the reg property of
child nodes according to the semantics of that bus's definition of the
reg property, and provide that value to the device driver for the child
node. Examples of reg parsing in Linux are:

drivers/i2c/i2c-core.c of_i2c_register_device() about 20 lines in. Note
that I2C addresses aren't simple integer values, but also encode some
flags too, such as 7-vs-10-bit addresses, and whether the DT node
represents a slave device that Linux should implement, or a regular device.

drivers/spi/spi.c of_register_spi_device() about 20 lines in. Here, the
address is the identify of the chip select wire, which may be driven by
the SPI controller, or via GPIOs, depending on the controller HW.

drivers/of/of_mdio.c of_mdio_parse_addr(). Here, the address is a simple
integer, with a range check.

drivers/mmc/core/core.c mmc_of_find_child_device(). At least SDIO
buses/devices (as opposed to eMMC/SD devices) appear to be able to host
multiple functions, and DT appears to be able to represent each function
as a separate child node of the SDIO controller.

drivers/spmi/spmi.c of_spmi_register_devices() about 10 lines in. I
don't know what SPMI is, but the interpretation of the reg property in
this code seems to have a few bus-specific rules.

drivers/nvmem/core.c of_nvmem_cell_get() about 25 lines in. I don't know
what nvmem is, but reg here seems to be a pretty simple base/size pair.

All of this discussion implies to me that drivers (for buses) really
should be calling different functions (or executing different local
custom code) to parse the reg property. The property is interpreted
quite differently depending on bus type.

Whether that means creating dev_get_addr_mmio() and dev_get_addr_i2c()
such that dev_get_addr() doesn't unconditionally translate addresses vs.
moving reg parsing into subsystem core code rather than drivers vs. any
other solution seems like an implementation detail. The main point is
that we certainly can't rely on a single dev_get_addr() that just works
for all reg properties.

All file and line count references above are relative to Linux kernel
version v4.4-rc8.