bcm2835: Getting DMA-busaddress for HW-register

Martin Sperl martin at sperl.org
Tue May 12 10:03:15 PDT 2015

> On 12.05.2015, at 04:59, Stephen Warren <swarren at wwwdotorg.org> wrote:
> The DT property shouldn't ever be read directly; parsing the raw data
> without using the DT helpers to do so will result in the ranges
> properties etc. not being correctly applied. While this does result in
> getting the value you /want/, it's not a legal way to get that value.
> Instead, you want something that ends up using the dma-ranges property.
> Eric Anholt sent a patch to do this upstream recently:
> https://lkml.org/lkml/2015/5/4/657
> [PATCH] ARM: bcm2835: Use 0x4 prefix for DMA bus addresses
> which contains:
>> diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
>> index 5734650..2df1b5c 100644
>> --- a/arch/arm/boot/dts/bcm2835.dtsi
>> +++ b/arch/arm/boot/dts/bcm2835.dtsi
>> @@ -15,6 +15,7 @@
>> 		#address-cells = <1>;
>> 		#size-cells = <1>;
>> 		ranges = <0x7e000000 0x20000000 0x02000000>;
>> +		dma-ranges = <0x40000000 0x00000000 0x1f000000>;

The question was how to get it done.

Adding dma-ranges to the device-tree is maybe part of the solution, but
what function do we need to call to get the “right” answer that is
also “legal”?

For the following device-tree fragment:
                spi at 7e204000 {
                        reg = <0x7e204000 0x1000>;

I can get the following addresses from the kernel:
0x20204000 - platform_get_resource(pdev, IORESOURCE_MEM, 0)->start: 
0xf0204000 - devm_ioremap_resource(&pdev->dev, res)
0x7e204000 - be32_to_cpup(of_get_address(pdev->dev.of_node, 0, NULL, NULL))

For the RPI2 the values are slightly different (on a foundation kernel):
0x3f204000 - platform_get_resource(pdev, IORESOURCE_MEM, 0)->start: 
0xbd01c000 - devm_ioremap_resource(&pdev->dev, res)
0x7e204000 - be32_to_cpup(of_get_address(pdev->dev.of_node, 0, NULL, NULL))

And the last one is the one that gives the RIGHT answer - which you say
is not legal.

Also those values do not change when adding/removing “dma-ranges” from
the tree.

As said, the sound/soc/bcm/bcm2835-i2s.c driver uses:
/* FIXME: Needs IOMMU support */
#define BCM2835_VCMMU_SHIFT             (0x7E000000 - 0x20000000)
        dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
                (dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG
                                          + BCM2835_VCMMU_SHIFT;
and i doubt that is that portable at all (not mentioning legal here)!

It is actually worse, as on the RPI2 it will DMA to the wrong address
(0x9d203000 instead of 0x7e203000) corrupting memory on that specific page.

So what _is_ the legal way to get the bus_address of the register base
for that device?


P.s: I tried also of_translate_address, but that also only
returns 0x20204000.

More information about the linux-rpi-kernel mailing list