bcm2835: Getting DMA-busaddress for HW-register

Stephen Warren swarren at wwwdotorg.org
Tue May 12 15:01:19 PDT 2015


On 05/12/2015 11:03 AM, Martin Sperl wrote:
>
>> 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”?

I'm sorry, I don't actually know. This is something you should ask on 
the main ARM Linux mailing list (or perhaps the main Linux kernel list). 
I'm sure someone there knows. Or maybe #armlinux on Freenode IRC.

It's possible this is a new feature that needs a new core function to be 
implemented.

> 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.

As some context, that last option would fail if I randomly added say 
0x1000 to the reg properties in DT, and hacked the ranges property to 
subtract this out again. That'd be a bit silly to do, but perfectly 
legal in that the correct way of parsing the DT still yields the correct 
physical address.

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

Yes, that likely only affect DMA addresses for DRAM. Since 
platform_get_resource() and devm_ioremap_resource() are used to map 
registers for CPU access (rather than DMA), dma-ranges likely doesn't 
affect them.

> 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.

Yes, that driver definitely needs fixing...

> So what _is_ the legal way to get the bus_address of the register base
> for that device?
>
> Thanks,
> 	Martin
>
> P.s: I tried also of_translate_address, but that also only
> returns 0x20204000.




More information about the linux-rpi-kernel mailing list