'Linux device drivers: mapping MMIO with `devm_of_iomap()` not working
I am writing a kernel platform device driver for booting group of remoteprocs. I am iterating over the groups of remoteprocs (child device nodes) and iomap them by their indexes inside the group with the help of for_each_child_of_node() macro. driver fails on the first devm_of_iomap() function call attempt. Now, I suspected that the platform device driver framework is not recognizing the resources inside the child device nodes (and I was right!), hence I have printed the device resources number from platform.c platform_get_resource() function and the result was 1 (which is the shared-buffer resource).
The Q: Maintaining the current DT format, how can I retrieve (or make them visible to the platform framework) these inner resources (adsp_dtcm, adsp_conf...etc) inside for loop?
// Device Tree
// ----------------------------
// Not the real values of course
// ----------------------------
dsp-cluster {
#address-cells = <2>;
#size-cells = <2>;
compatible = "xxxxxx,dsp_remoteproc";
dsp_count = <2>;
reg = <0x0 0x10000000 0x0 0x100000>; // the only one that recognized by platform framework
reg-names = "share-buffer";
dsp@0 {
reg = <0x0 0xfff00000 0x0 0x40000>,
<0x0 0xfffc0000 0x0 0x20000>,
<0x0 0xfff00000 0x0 0x20000>,
<0x0 0xfffa0000 0x0 0x20000>,
<0x0 0xfffc0000 0x0 0x4000>,
<0x0 0xfffc8000 0x0 0x8000>,
<0x0 0xfffd0000 0x0 0x8000>;
reg-names = "adsp_dtcm", "adsp_conf", "vdsp_dtcm", "vdsp_conf",
"cdsp_dtcm", "cdsp_itcm", "cdsp_conf";
};
dsp@1 {
reg = <0x0 0x10400000 0x0 0x40000>,
<0x0 0xxxx0000 0x0 0x20000>,
<0x0 0xyyy00000 0x0 0x20000>,
<0x0 0xzzza0000 0x0 0x20000>,
<0x0 0xxxxc0000 0x0 0x4000>,
<0x0 0xyyyc8000 0x0 0x8000>,
<0x0 0xeeed0000 0x0 0x8000>;
reg-names = "adsp_dtcm", "adsp_conf", "vdsp_dtcm", "vdsp_conf",
"cdsp_dtcm", "cdsp_itcm", "cdsp_conf";
};
};
My driver code (only the section that trying to iterate and iomap these all resources inside dsp@0 and dsp@1):
static int dsp_remoteproc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
u32 dsp_count = 1;
int ret;
struct device_node *dev_node = dev->of_node;
struct device_node *child = NULL;
unsigned j = 0;
if (of_property_read_u32(dev->of_node, "dsp_count ", &dsp_count))
dev_warn(dev, "dsp_count property not exist, defaulting to 1\n");
for_each_child_of_node(dev_node, child) {
if (!child || (j++ > dsp_count))
break;
void __iomem *iomap_ret;
// iomap adsp conf regs
iomap_ret = devm_of_iomap(dev, dev_node, 1, NULL);
if (IS_ERR(iomap_ret))
return -ENODEV;
}
Solution 1:[1]
Translation of addresses in a node's reg property relies on the presence of a ranges property in the parent node. This is checked by the of_translate_one function in "drivers/of/address.c", an extract of which is shown below:
/*
* Normally, an absence of a "ranges" property means we are
* crossing a non-translatable boundary, and thus the addresses
* below the current cannot be converted to CPU physical ones.
* Unfortunately, while this is very clear in the spec, it's not
* what Apple understood, and they do have things like /uni-n or
* /ht nodes with no "ranges" property and a lot of perfectly
* useable mapped devices below them. Thus we treat the absence of
* "ranges" as equivalent to an empty "ranges" property which means
* a 1:1 translation at that level. It's up to the caller not to try
* to translate addresses that aren't supposed to be translated in
* the first place. --BenH.
*
* As far as we know, this damage only exists on Apple machines, so
* This code is only enabled on powerpc. --gcl
*
* This quirk also applies for 'dma-ranges' which frequently exist in
* child nodes without 'dma-ranges' in the parent nodes. --RobH
*/
ranges = of_get_property(parent, rprop, &rlen);
if (ranges == NULL && !of_empty_ranges_quirk(parent) &&
strcmp(rprop, "dma-ranges")) {
pr_debug("no ranges; cannot translate\n");
return 1;
}
Here, parent is the parent node, rprop is the string "ranges" for a normal range (the same function is also used for translating DMA addresses, where rprop would be the string "dma-ranges"), and the non-zero return value indicates failure. (Don't worry about the !of_empty_ranges_quirk(parent). That is just for some weird special cases.) If the parent node doesn't have the ranges property (for a normal range) then the ranges variable will be NULL and the function will return 1 to indicate failure to translate the address.
You may wonder why the code doesn't search up the tree until it finds a ranges property. The reason is that not all reg properties are used for translating physical addresses. This is explained in Device Tree Usage # Ranges (Address Translation) when discussing the reg property for the rtc@58 node (an I2C device) whose parent is the i2c@1,0 node:
You should also notice that there is no
rangesproperty in the i2c@1,0 node. The reason for this is that unlike the external bus, devices on the i2c bus are not memory mapped on the CPU's address domain. Instead, the CPU indirectly accesses the rtc@58 device via the i2c@1,0 device. The lack of arangesproperty means that a device cannot be directly accessed by any device other than it's parent.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
