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.
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to