* DT vs ARM static mappings
@ 2011-09-20 11:51 Pawel Moll
2011-09-20 12:58 ` Rob Herring
2011-09-21 17:49 ` Nicolas Pitre
0 siblings, 2 replies; 15+ messages in thread
From: Pawel Moll @ 2011-09-20 11:51 UTC (permalink / raw)
To: linux-arm-kernel
Hi All,
Apologies for the length of the text below, but the problem is
complex... (or at least it seems to be)
While working on DT support for ARM Versatile Express I faced an
interesting problem... Some background first, to set a common ground and
test my understanding of the problem ;-)
ARM machine description contains a "map_io" method, which is used to
create static memory mappings (using iotable_init() function) for things
like peripherals or SRAMs. At least that's the theory, because most of
the platforms are doing much more stuff there, like clocking/GPIOs/UARTs
initialization, hardware probing etc.
Now the Versatile Express platform: it consists of a motherboard with a
set of peripherals and a processor daughterboard (core tile), both
connected via a static memory bus, which is mapped into processor's
physical address space. The motherboard can be shared between different
types of the tiles (eg. A9, A5, A15 etc.). The present one is probed byt
he motherboard firmware and exposed in "system registers".
Everything is fine so far. The interesting part starts here:
http://infocenter.arm.com/help/topic/com.arm.doc.dui0447e/CACIHGFE.html
In brief, depending on the configuration, the system can have one of
two, totally different, memory maps (please, do spare me the "but why
did they do that" comments - not my idea nor decision, I just have to
live with this ;-), depending on the core tile being used.
In result, the static mapping as defined currently in
arch/arm/mach-vexpress/v2m.c for A9 variant:
#define V2M_PA_CS7 0x10000000
static struct map_desc v2m_io_desc[] __initdata = {
{
.virtual = __MMIO_P2V(V2M_PA_CS7),
.pfn = __phys_to_pfn(V2M_PA_CS7),
.length = SZ_128K,
.type = MT_DEVICE,
},
};
is no longer valid for A5/A15. It would rather look like this:
#define V2M_PA_CS3 0x1c000000
static struct map_desc v2m_io_desc[] __initdata = {
{
.virtual = __MMIO_P2V(V2M_PA_CS3),
.pfn = __phys_to_pfn(V2M_PA_CS3),
.length = SZ_2M,
.type = MT_DEVICE,
},
};
Not only the peripherals base address is changed but also "internal"
alignment, thus offsets to peripherals. Some of them are not being
ioremap()ed, but directly used via the static mapping and MMIO_P2V macro
(like "readl(MMIO_P2V(V2M_SYS_PROCID0))" in v2m_populate_ct_desc(void)
function). For example, these two:
#define V2M_SYSREGS (V2M_PA_CS7 + 0x00000000)
#define V2M_SYSCTL (V2M_PA_CS7 + 0x00001000)
would have to become:
#define V2M_SYSREGS (V2M_PA_CS3 + 0x00010000)
#define V2M_SYSCTL (V2M_PA_CS3 + 0x00020000)
My current DTS for the original memory map looks like that (fragments):
{
motherboard {
ranges = <7 0 0x10000000 0x00020000>;
#address-cells = <2>; // SMB chipselect number and offset
#size-cells = <1>;
peripherals at 7 {
ranges = <0 7 0 0x20000>;
#address-cells = <1>;
#size-cells = <1>;
sysreg at 00000 {
reg = <0x00000 0x1000>;
};
sysctl at 01000 {
reg = <0x01000 0x1000>;
};
}
}
}
DTS for the second memory map would just have the addresses changed.
Unfortunately, because of the static mappings being hardcoded in the
board support file, one kernel won't Just Work (TM) with different DTBs.
Of course the simplest solution would be to define two different
compatible values, eg. "arm,vexpress-legacy" would execute the current
map_io implementation, while "arm,vexpress-rs1" would use different one,
setting up the other map_desc (the MMIO_P2V macro must die of course,
replaced with a runtime-defined virtual base address for the
peripherals).
If you believe that's what I should do, say it and stop reading :-)
To my mind it looked like the whole mechanism was not flexible enough,
so I wanted to explore other options...
The obvious one was to describe the required static mapping in the DTS.
I don't like this idea, though. It can hardly be called "hardware
description". Besides, what node would carry such data? "chosen"?
Hardly...
Would it contain a "regs" property with the physical address and
"virtual-reg" with the virtual one? Again, doesn't sound right to me
(especially the virtual bit, however the virtual address could be common
between different variants and be defined in the board support code, not
the DTS).
I have considered a reference (phandle or an alias?) to the node to be
mapped ("peripherals" in my case), but where to define this reference?
Any ideas?
There is an additional problem here... The "map_io" is executed before
the tree is un-flattened, so:
1. One can't simply use "of_find_matching_node()" (as in the latest l2x0
patches) to find the interesting nodes - the only way of going through
the tree is raw of_scan_flat_dt() function. Therefore any conditions
more complex then string comparison with the (full) node name are
problematic.
2. The tree mappings (ranges) are not resolved yet, so one can't simply
get the effective address of a node. Only "raw" properties are
available, so all one can get scanning for "peripherals at 7" node is "0 7
0 0x20000" array, instead of the "0x10000000 0x00020000" that is really
important.
Initially I wanted to find the mentioned devices and create individual
mappings for them, so the MMIO_P2V would be still valid (if slightly
"abused"), but I failed due to the problems mentioned above. And I can't
delay this operation till the tree is un-flattened, as the core tile
must be probed (via sysreg) in map_io (tile's specific code must be able
to create its own mappings):
static void __init v2m_map_io(void)
{
iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
v2m_populate_ct_desc();
ct_desc->map_io();
}
Any comments, ideas and suggestions how to tackle this situation are
more than welcome.
Cheers!
Pawe?
^ permalink raw reply [flat|nested] 15+ messages in thread
* DT vs ARM static mappings
2011-09-20 11:51 DT vs ARM static mappings Pawel Moll
@ 2011-09-20 12:58 ` Rob Herring
2011-09-20 14:02 ` Pawel Moll
2011-09-21 17:49 ` Nicolas Pitre
1 sibling, 1 reply; 15+ messages in thread
From: Rob Herring @ 2011-09-20 12:58 UTC (permalink / raw)
To: linux-arm-kernel
Pawel,
On 09/20/2011 06:51 AM, Pawel Moll wrote:
> Hi All,
>
> Apologies for the length of the text below, but the problem is
> complex... (or at least it seems to be)
>
> While working on DT support for ARM Versatile Express I faced an
> interesting problem... Some background first, to set a common ground and
> test my understanding of the problem ;-)
>
> ARM machine description contains a "map_io" method, which is used to
> create static memory mappings (using iotable_init() function) for things
> like peripherals or SRAMs. At least that's the theory, because most of
> the platforms are doing much more stuff there, like clocking/GPIOs/UARTs
> initialization, hardware probing etc.
>
> Now the Versatile Express platform: it consists of a motherboard with a
> set of peripherals and a processor daughterboard (core tile), both
> connected via a static memory bus, which is mapped into processor's
> physical address space. The motherboard can be shared between different
> types of the tiles (eg. A9, A5, A15 etc.). The present one is probed byt
> he motherboard firmware and exposed in "system registers".
>
> Everything is fine so far. The interesting part starts here:
>
> http://infocenter.arm.com/help/topic/com.arm.doc.dui0447e/CACIHGFE.html
>
> In brief, depending on the configuration, the system can have one of
> two, totally different, memory maps (please, do spare me the "but why
> did they do that" comments - not my idea nor decision, I just have to
> live with this ;-), depending on the core tile being used.
>
> In result, the static mapping as defined currently in
> arch/arm/mach-vexpress/v2m.c for A9 variant:
>
> #define V2M_PA_CS7 0x10000000
>
> static struct map_desc v2m_io_desc[] __initdata = {
> {
> .virtual = __MMIO_P2V(V2M_PA_CS7),
> .pfn = __phys_to_pfn(V2M_PA_CS7),
> .length = SZ_128K,
> .type = MT_DEVICE,
> },
> };
>
> is no longer valid for A5/A15. It would rather look like this:
>
> #define V2M_PA_CS3 0x1c000000
>
> static struct map_desc v2m_io_desc[] __initdata = {
> {
> .virtual = __MMIO_P2V(V2M_PA_CS3),
> .pfn = __phys_to_pfn(V2M_PA_CS3),
> .length = SZ_2M,
> .type = MT_DEVICE,
> },
> };
>
> Not only the peripherals base address is changed but also "internal"
> alignment, thus offsets to peripherals. Some of them are not being
> ioremap()ed, but directly used via the static mapping and MMIO_P2V macro
> (like "readl(MMIO_P2V(V2M_SYS_PROCID0))" in v2m_populate_ct_desc(void)
> function). For example, these two:
>
> #define V2M_SYSREGS (V2M_PA_CS7 + 0x00000000)
> #define V2M_SYSCTL (V2M_PA_CS7 + 0x00001000)
>
> would have to become:
>
> #define V2M_SYSREGS (V2M_PA_CS3 + 0x00010000)
> #define V2M_SYSCTL (V2M_PA_CS3 + 0x00020000)
>
> My current DTS for the original memory map looks like that (fragments):
>
> {
> motherboard {
> ranges = <7 0 0x10000000 0x00020000>;
> #address-cells = <2>; // SMB chipselect number and offset
> #size-cells = <1>;
>
> peripherals at 7 {
> ranges = <0 7 0 0x20000>;
> #address-cells = <1>;
> #size-cells = <1>;
>
> sysreg at 00000 {
> reg = <0x00000 0x1000>;
> };
>
> sysctl at 01000 {
> reg = <0x01000 0x1000>;
> };
> }
> }
> }
>
> DTS for the second memory map would just have the addresses changed.
> Unfortunately, because of the static mappings being hardcoded in the
> board support file, one kernel won't Just Work (TM) with different DTBs.
>
> Of course the simplest solution would be to define two different
> compatible values, eg. "arm,vexpress-legacy" would execute the current
> map_io implementation, while "arm,vexpress-rs1" would use different one,
> setting up the other map_desc (the MMIO_P2V macro must die of course,
> replaced with a runtime-defined virtual base address for the
> peripherals).
>
> If you believe that's what I should do, say it and stop reading :-)
>
Yes. Different tiles are fundamentally different boards, so they should
have different DTs. Using includes should help minimize duplication though.
Think about it this way. How would you solve this without DT? You would
have a bunch of duplicated data in the kernel for the different configs.
So you're not any worse off in this regard and still have the other
advantages of DT.
> To my mind it looked like the whole mechanism was not flexible enough,
> so I wanted to explore other options...
>
> The obvious one was to describe the required static mapping in the DTS.
> I don't like this idea, though. It can hardly be called "hardware
> description". Besides, what node would carry such data? "chosen"?
> Hardly...
>
> Would it contain a "regs" property with the physical address and
> "virtual-reg" with the virtual one? Again, doesn't sound right to me
> (especially the virtual bit, however the virtual address could be common
> between different variants and be defined in the board support code, not
> the DTS).
>
> I have considered a reference (phandle or an alias?) to the node to be
> mapped ("peripherals" in my case), but where to define this reference?
> Any ideas?
In "chosen" like the kernel command line would be the place, but I don't
think that is the right approach. Chosen is really for things that
change frequently and this doesn't really fall in that category.
>
> There is an additional problem here... The "map_io" is executed before
> the tree is un-flattened, so:
>
> 1. One can't simply use "of_find_matching_node()" (as in the latest l2x0
> patches) to find the interesting nodes - the only way of going through
> the tree is raw of_scan_flat_dt() function. Therefore any conditions
> more complex then string comparison with the (full) node name are
> problematic.
>
> 2. The tree mappings (ranges) are not resolved yet, so one can't simply
> get the effective address of a node. Only "raw" properties are
> available, so all one can get scanning for "peripherals at 7" node is "0 7
> 0 0x20000" array, instead of the "0x10000000 0x00020000" that is really
> important.
>
If you add a compatible field to "motherboard" node, then you can read
the ranges.
> Initially I wanted to find the mentioned devices and create individual
> mappings for them, so the MMIO_P2V would be still valid (if slightly
> "abused"), but I failed due to the problems mentioned above. And I can't
> delay this operation till the tree is un-flattened, as the core tile
> must be probed (via sysreg) in map_io (tile's specific code must be able
> to create its own mappings):
Do you really need MMIO_P2V? If you have fixed virtual addresses in the
kernel and can pull the phys addresses from DT to populate the iotable,
is that sufficient?
>
> static void __init v2m_map_io(void)
> {
> iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
> v2m_populate_ct_desc();
> ct_desc->map_io();
> }
>
> Any comments, ideas and suggestions how to tackle this situation are
> more than welcome.
>
Generally, the trend is to get rid of static mappings as much as
possible. Doing that first might simplify things.
Rob
> Cheers!
>
> Pawe?
>
>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 15+ messages in thread
* DT vs ARM static mappings
2011-09-20 12:58 ` Rob Herring
@ 2011-09-20 14:02 ` Pawel Moll
2011-09-20 14:37 ` Rob Herring
0 siblings, 1 reply; 15+ messages in thread
From: Pawel Moll @ 2011-09-20 14:02 UTC (permalink / raw)
To: linux-arm-kernel
> > Of course the simplest solution would be to define two different
> > compatible values, eg. "arm,vexpress-legacy" would execute the current
> > map_io implementation, while "arm,vexpress-rs1" would use different one,
> > setting up the other map_desc (the MMIO_P2V macro must die of course,
> > replaced with a runtime-defined virtual base address for the
> > peripherals).
> >
> > If you believe that's what I should do, say it and stop reading :-)
>
> Yes. Different tiles are fundamentally different boards, so they should
> have different DTs. Using includes should help minimize duplication though.
You've misunderstood me or (most likely ;-) probably I wasn't clear
enough.
There is no doubt the DTs will be different across the "portfolio".
We already have (patches soon) vexpress-v2p-ca9.dts that includes
vexpress-v2m-legacy.dtsi.
A5 will be vexpress-v2p-ca5p.dts+vexpress-v2m-rs1.dtsi, A15
vexpress-v2p-ca15.dts+vexpress-v2m-rs1.dtsi (notice that the A5/A15 are
sharing the v2m bit, as the motherboard is common).
My point is that we should be able to handle _all_ of them using one
DT_MACHINE_START with a single compat value "arm,vexpress". The only
problem with this (so far) is the mapping.
> Think about it this way. How would you solve this without DT? You
> would have a bunch of duplicated data in the kernel for the different
> configs. So you're not any worse off in this regard and still have the
> other advantages of DT.
Exactly my point :-) I want to have as little duplication as possible.
And the static mapping issue is in the way.
> > To my mind it looked like the whole mechanism was not flexible enough,
> > so I wanted to explore other options...
> >
> > The obvious one was to describe the required static mapping in the DTS.
> > I don't like this idea, though. It can hardly be called "hardware
> > description". Besides, what node would carry such data? "chosen"?
> > Hardly...
> >
> > Would it contain a "regs" property with the physical address and
> > "virtual-reg" with the virtual one? Again, doesn't sound right to me
> > (especially the virtual bit, however the virtual address could be common
> > between different variants and be defined in the board support code, not
> > the DTS).
> >
> > I have considered a reference (phandle or an alias?) to the node to be
> > mapped ("peripherals" in my case), but where to define this reference?
> > Any ideas?
>
> In "chosen" like the kernel command line would be the place, but I don't
> think that is the right approach. Chosen is really for things that
> change frequently and this doesn't really fall in that category.
Again, no argument from me here :-)
The question is - where should it be?
> > There is an additional problem here... The "map_io" is executed before
> > the tree is un-flattened, so:
> >
> > 1. One can't simply use "of_find_matching_node()" (as in the latest l2x0
> > patches) to find the interesting nodes - the only way of going through
> > the tree is raw of_scan_flat_dt() function. Therefore any conditions
> > more complex then string comparison with the (full) node name are
> > problematic.
> >
> > 2. The tree mappings (ranges) are not resolved yet, so one can't simply
> > get the effective address of a node. Only "raw" properties are
> > available, so all one can get scanning for "peripherals at 7" node is "0 7
> > 0 0x20000" array, instead of the "0x10000000 0x00020000" that is really
> > important.
>
> If you add a compatible field to "motherboard" node, then you can read
> the ranges.
... and then and then scan for the sysregs, and add the offset and base
together... Sounds to me like duplication of the of_translate_*()?
> > Initially I wanted to find the mentioned devices and create individual
> > mappings for them, so the MMIO_P2V would be still valid (if slightly
> > "abused"), but I failed due to the problems mentioned above. And I can't
> > delay this operation till the tree is un-flattened, as the core tile
> > must be probed (via sysreg) in map_io (tile's specific code must be able
> > to create its own mappings):
>
> Do you really need MMIO_P2V? If you have fixed virtual addresses in the
> kernel and can pull the phys addresses from DT to populate the iotable,
> is that sufficient?
For the third time, 100% agree :-) Well, 90%.
What I need is:
1. Get the phys address from DT. But how? This is getting as back to my
complaints about still-flat tree and ranges, the node to be used to
describe the mapping.
2. The offset inside the mapping will be different (for sysregs it will
be 0 for old mapping, 0x10000 for the new one), so I have to work it out
from the tree as well. And as we are in map_io, the tree is still flat
and... read 1 :-)
> Generally, the trend is to get rid of static mappings as much as
> possible. Doing that first might simplify things.
You can't do ioremap() before kmalloc() is up and running (correct me if
I am wrong), at least you can't do this in map_io. So the static mapping
is a must sometimes. And actually, with the latest Nico's changes:
http://thread.gmane.org/gmane.linux.ports.arm.kernel/132762
it may even be preferred for peripherals (one mapping shared across all
users).
Cheers!
Pawe?
^ permalink raw reply [flat|nested] 15+ messages in thread
* DT vs ARM static mappings
2011-09-20 14:02 ` Pawel Moll
@ 2011-09-20 14:37 ` Rob Herring
2011-09-20 16:16 ` Pawel Moll
0 siblings, 1 reply; 15+ messages in thread
From: Rob Herring @ 2011-09-20 14:37 UTC (permalink / raw)
To: linux-arm-kernel
Pawel,
On 09/20/2011 09:02 AM, Pawel Moll wrote:
>>> Of course the simplest solution would be to define two different
>>> compatible values, eg. "arm,vexpress-legacy" would execute the current
>>> map_io implementation, while "arm,vexpress-rs1" would use different one,
>>> setting up the other map_desc (the MMIO_P2V macro must die of course,
>>> replaced with a runtime-defined virtual base address for the
>>> peripherals).
>>>
>>> If you believe that's what I should do, say it and stop reading :-)
>>
>> Yes. Different tiles are fundamentally different boards, so they should
>> have different DTs. Using includes should help minimize duplication though.
>
> You've misunderstood me or (most likely ;-) probably I wasn't clear
> enough.
>
> There is no doubt the DTs will be different across the "portfolio".
>
> We already have (patches soon) vexpress-v2p-ca9.dts that includes
> vexpress-v2m-legacy.dtsi.
>
> A5 will be vexpress-v2p-ca5p.dts+vexpress-v2m-rs1.dtsi, A15
> vexpress-v2p-ca15.dts+vexpress-v2m-rs1.dtsi (notice that the A5/A15 are
> sharing the v2m bit, as the motherboard is common).
>
> My point is that we should be able to handle _all_ of them using one
> DT_MACHINE_START with a single compat value "arm,vexpress". The only
> problem with this (so far) is the mapping.
>
Yes, you should have 1 DT_MACHINE_START, but arm,vexpress is too
generic. You can and should have a list of compatible strings for each
board/machine.
>> Think about it this way. How would you solve this without DT? You
>> would have a bunch of duplicated data in the kernel for the different
>> configs. So you're not any worse off in this regard and still have the
>> other advantages of DT.
>
> Exactly my point :-) I want to have as little duplication as possible.
> And the static mapping issue is in the way.
>
>>> To my mind it looked like the whole mechanism was not flexible enough,
>>> so I wanted to explore other options...
>>>
>>> The obvious one was to describe the required static mapping in the DTS.
>>> I don't like this idea, though. It can hardly be called "hardware
>>> description". Besides, what node would carry such data? "chosen"?
>>> Hardly...
>>>
>>> Would it contain a "regs" property with the physical address and
>>> "virtual-reg" with the virtual one? Again, doesn't sound right to me
>>> (especially the virtual bit, however the virtual address could be common
>>> between different variants and be defined in the board support code, not
>>> the DTS).
>>>
>>> I have considered a reference (phandle or an alias?) to the node to be
>>> mapped ("peripherals" in my case), but where to define this reference?
>>> Any ideas?
>>
>> In "chosen" like the kernel command line would be the place, but I don't
>> think that is the right approach. Chosen is really for things that
>> change frequently and this doesn't really fall in that category.
>
> Again, no argument from me here :-)
>
> The question is - where should it be?
>
Nowhere. It's an OS specific issue, not a h/w issue.
>>> There is an additional problem here... The "map_io" is executed before
>>> the tree is un-flattened, so:
>>>
>>> 1. One can't simply use "of_find_matching_node()" (as in the latest l2x0
>>> patches) to find the interesting nodes - the only way of going through
>>> the tree is raw of_scan_flat_dt() function. Therefore any conditions
>>> more complex then string comparison with the (full) node name are
>>> problematic.
>>>
>>> 2. The tree mappings (ranges) are not resolved yet, so one can't simply
>>> get the effective address of a node. Only "raw" properties are
>>> available, so all one can get scanning for "peripherals at 7" node is "0 7
>>> 0 0x20000" array, instead of the "0x10000000 0x00020000" that is really
>>> important.
>>
>> If you add a compatible field to "motherboard" node, then you can read
>> the ranges.
>
> ... and then and then scan for the sysregs, and add the offset and base
> together... Sounds to me like duplication of the of_translate_*()?
>
>>> Initially I wanted to find the mentioned devices and create individual
>>> mappings for them, so the MMIO_P2V would be still valid (if slightly
>>> "abused"), but I failed due to the problems mentioned above. And I can't
>>> delay this operation till the tree is un-flattened, as the core tile
>>> must be probed (via sysreg) in map_io (tile's specific code must be able
>>> to create its own mappings):
>>
>> Do you really need MMIO_P2V? If you have fixed virtual addresses in the
>> kernel and can pull the phys addresses from DT to populate the iotable,
>> is that sufficient?
>
> For the third time, 100% agree :-) Well, 90%.
>
> What I need is:
>
> 1. Get the phys address from DT. But how? This is getting as back to my
> complaints about still-flat tree and ranges, the node to be used to
> describe the mapping.
>
> 2. The offset inside the mapping will be different (for sysregs it will
> be 0 for old mapping, 0x10000 for the new one), so I have to work it out
> from the tree as well. And as we are in map_io, the tree is still flat
> and... read 1 :-)
So create a mapping per peripheral rather than per chip select. Then the
virtual address can always be the same.
>
>> Generally, the trend is to get rid of static mappings as much as
>> possible. Doing that first might simplify things.
>
> You can't do ioremap() before kmalloc() is up and running (correct me if
> I am wrong), at least you can't do this in map_io. So the static mapping
> is a must sometimes. And actually, with the latest Nico's changes:
>
Correct. You can't do ioremap until init_irq. map_io and init_early are
too early. My point was if you can delay h/w access then you can remove
the static mappings. But yes, we generally can't remove them all. SCU
and LL debug uart are 2 examples.
For the short term, I would just have 2 static iotables and select the
right one based on the board's (or motherboard's) compatible string.
Long term, we should look into implementing a common early DT address
parsing function.
Rob
> http://thread.gmane.org/gmane.linux.ports.arm.kernel/132762
>
> it may even be preferred for peripherals (one mapping shared across all
> users).
>
> Cheers!
>
> Pawe?
>
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* DT vs ARM static mappings
2011-09-20 14:37 ` Rob Herring
@ 2011-09-20 16:16 ` Pawel Moll
2011-09-20 19:28 ` Arnd Bergmann
0 siblings, 1 reply; 15+ messages in thread
From: Pawel Moll @ 2011-09-20 16:16 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, 2011-09-20 at 15:37 +0100, Rob Herring wrote
> > My point is that we should be able to handle _all_ of them using one
> > DT_MACHINE_START with a single compat value "arm,vexpress". The only
> > problem with this (so far) is the mapping.
>
> Yes, you should have 1 DT_MACHINE_START, but arm,vexpress is too
> generic. You can and should have a list of compatible strings for each
> board/machine.
Our DTS has:
compatible = "arm,vexpress-v2p-ca9", "arm,vexpress";
and v2m.c:
static const char *v2m_dt_match[] __initconst = {
"arm,vexpress",
NULL,
};
DT_MACHINE_START(VEXPRESS_DT, "ARM Versatile Express")
.map_io = v2m_map_io,
.init_early = v2m_init_early,
.init_irq = v2m_init_irq,
.timer = &v2m_timer,
.init_machine = v2m_dt_init,
.dt_compat = v2m_dt_match,
MACHINE_END
Isn't it what you meant?
Essentially I see two ways of doing what we are discussing:
1. Two DT_MACHINE_START, one matching "arm,vexpress-legacy" with map_io
= v2m_map_io_legacy and second matching "arm,vexpress-rs1" with map_io =
v2m_map_io_rs1,
2. Single DT_MACHINE_START matching (the most generic) "arm,vexpress"
and doing (rougly) this in v2m_map_io:
of_scan_flat_dt(v2m_dt_iotable_init, NULL);
v2m_dt_iotable_init(...)
{
if (depth != 0)
return 0;
if (of_flat_dt_is_compatible(node, "arm,vexpress-legacy"))
iotable_init(v2m_io_desc_legacy);
else (of_flat_dt_is_compatible(node, "arm,vexpress-rs1"))
iotable_init(v2m_io_desc_rs1);
else
panic();
}
Neither of them seem particularly appealing... ;-)
> >> In "chosen" like the kernel command line would be the place, but I don't
> >> think that is the right approach. Chosen is really for things that
> >> change frequently and this doesn't really fall in that category.
> >
> > Again, no argument from me here :-)
> >
> > The question is - where should it be?
>
> Nowhere. It's an OS specific issue, not a h/w issue.
That's exactly why I didn't like this idea in the first place. This
doesn't change the fact that current infrastructure isn't really helpful
here.
> So create a mapping per peripheral rather than per chip select. Then the
> virtual address can always be the same.
As I said (see below) this is exactly what I wanted to do, but I was
defeated by the reality :-)
On Tue, 2011-09-20 at 12:51 +0100, Pawel Moll wrote:
> > > Initially I wanted to find the mentioned devices and create individual
> > > mappings for them, so the MMIO_P2V would be still valid (if slightly
> > > "abused"), but I failed due to the problems mentioned above. And I can't
> > > delay this operation till the tree is un-flattened, as the core tile
> > > must be probed (via sysreg) in map_io (tile's specific code must be able
> > > to create its own mappings):
> >> Generally, the trend is to get rid of static mappings as much as
> >> possible. Doing that first might simplify things.
> >
> > You can't do ioremap() before kmalloc() is up and running (correct me if
> > I am wrong), at least you can't do this in map_io. So the static mapping
> > is a must sometimes. And actually, with the latest Nico's changes:
> >
> Correct. You can't do ioremap until init_irq. map_io and init_early are
> too early. My point was if you can delay h/w access then you can remove
> the static mappings. But yes, we generally can't remove them all. SCU
> and LL debug uart are 2 examples.
In my case it's sysreg and sysctl. There are two more users of static
mappings: timer01 and timer23, but they could at some point do ioremap()
on their own (especially with Nico's changes).
> For the short term, I would just have 2 static iotables and select the
> right one based on the board's (or motherboard's) compatible string.
Yes, as mentioned above. This doesn't help with the sysreg offset
problem though. I may just scan the flat tree looking for their
particular names and getting raw offset from their regs... Sounds like a
hack, though.
> Long term, we should look into implementing a common early DT address
> parsing function.
Well, assuming that we want to have them at all. I'm not convinced,
frankly ;-)
Pawe?
^ permalink raw reply [flat|nested] 15+ messages in thread
* DT vs ARM static mappings
2011-09-20 16:16 ` Pawel Moll
@ 2011-09-20 19:28 ` Arnd Bergmann
2011-09-21 9:41 ` Pawel Moll
2011-09-22 16:23 ` Pawel Moll
0 siblings, 2 replies; 15+ messages in thread
From: Arnd Bergmann @ 2011-09-20 19:28 UTC (permalink / raw)
To: linux-arm-kernel
On Tuesday 20 September 2011, Pawel Moll wrote:
> On Tue, 2011-09-20 at 15:37 +0100, Rob Herring wrote
> > > My point is that we should be able to handle _all_ of them using one
> > > DT_MACHINE_START with a single compat value "arm,vexpress". The only
> > > problem with this (so far) is the mapping.
> >
> > Yes, you should have 1 DT_MACHINE_START, but arm,vexpress is too
> > generic. You can and should have a list of compatible strings for each
> > board/machine.
>
> Our DTS has:
>
> compatible = "arm,vexpress-v2p-ca9", "arm,vexpress";
>
> and v2m.c:
>
> static const char *v2m_dt_match[] __initconst = {
> "arm,vexpress",
> NULL,
> };
>
> DT_MACHINE_START(VEXPRESS_DT, "ARM Versatile Express")
> .map_io = v2m_map_io,
> .init_early = v2m_init_early,
> .init_irq = v2m_init_irq,
> .timer = &v2m_timer,
> .init_machine = v2m_dt_init,
> .dt_compat = v2m_dt_match,
> MACHINE_END
>
> Isn't it what you meant?
>
> Essentially I see two ways of doing what we are discussing:
>
> 1. Two DT_MACHINE_START, one matching "arm,vexpress-legacy" with map_io
> = v2m_map_io_legacy and second matching "arm,vexpress-rs1" with map_io =
> v2m_map_io_rs1,
>
> 2. Single DT_MACHINE_START matching (the most generic) "arm,vexpress"
> and doing (rougly) this in v2m_map_io:
>
> of_scan_flat_dt(v2m_dt_iotable_init, NULL);
>
> v2m_dt_iotable_init(...)
> {
> if (depth != 0)
> return 0;
> if (of_flat_dt_is_compatible(node, "arm,vexpress-legacy"))
> iotable_init(v2m_io_desc_legacy);
> else (of_flat_dt_is_compatible(node, "arm,vexpress-rs1"))
> iotable_init(v2m_io_desc_rs1);
> else
> panic();
> }
>
> Neither of them seem particularly appealing... ;-)
But I think both ways would be acceptable in the end. It's not a lot
of extra code either way. In the second case, I would probably have
the legacy case as a special variant of the map_io function and have
all others be the default instead of falling back to panic though.
> > >> In "chosen" like the kernel command line would be the place, but I don't
> > >> think that is the right approach. Chosen is really for things that
> > >> change frequently and this doesn't really fall in that category.
> > >
> > > Again, no argument from me here :-)
> > >
> > > The question is - where should it be?
> >
> > Nowhere. It's an OS specific issue, not a h/w issue.
>
> That's exactly why I didn't like this idea in the first place. This
> doesn't change the fact that current infrastructure isn't really helpful
> here.
Agreed, I think that approach would be much worse.
> > >> Generally, the trend is to get rid of static mappings as much as
> > >> possible. Doing that first might simplify things.
> > >
> > > You can't do ioremap() before kmalloc() is up and running (correct me if
> > > I am wrong), at least you can't do this in map_io. So the static mapping
> > > is a must sometimes. And actually, with the latest Nico's changes:
> > >
> > Correct. You can't do ioremap until init_irq. map_io and init_early are
> > too early. My point was if you can delay h/w access then you can remove
> > the static mappings. But yes, we generally can't remove them all. SCU
> > and LL debug uart are 2 examples.
>
> In my case it's sysreg and sysctl. There are two more users of static
> mappings: timer01 and timer23, but they could at some point do ioremap()
> on their own (especially with Nico's changes).
Well, I think with Nico's cahnges, you /can/ actually do ioremap for
areas that have been mapped through the iotable before kmalloc is up.
IIRC, omap does this for a number of peripherals.
It's a bit of a hack, but I think it's much better than taking hardcoded
addresses.
> > For the short term, I would just have 2 static iotables and select the
> > right one based on the board's (or motherboard's) compatible string.
>
> Yes, as mentioned above. This doesn't help with the sysreg offset
> problem though. I may just scan the flat tree looking for their
> particular names and getting raw offset from their regs... Sounds like a
> hack, though.
With the combination of the points mentioned above, you should be
able to do:
- map the entire I/O area in map_io(), depending on the board
- have an __iomem pointer for the sysreg
- populate that pointer using of_iomap from the device tree address
before you first access it.
Do you think that would work?
Arnd
^ permalink raw reply [flat|nested] 15+ messages in thread
* DT vs ARM static mappings
2011-09-20 19:28 ` Arnd Bergmann
@ 2011-09-21 9:41 ` Pawel Moll
2011-09-21 9:59 ` Dave Martin
2011-09-22 16:23 ` Pawel Moll
1 sibling, 1 reply; 15+ messages in thread
From: Pawel Moll @ 2011-09-21 9:41 UTC (permalink / raw)
To: linux-arm-kernel
> > 2. Single DT_MACHINE_START matching (the most generic) "arm,vexpress"
> > and doing (rougly) this in v2m_map_io:
> >
> > of_scan_flat_dt(v2m_dt_iotable_init, NULL);
> >
> > v2m_dt_iotable_init(...)
> > {
> > if (depth != 0)
> > return 0;
> > if (of_flat_dt_is_compatible(node, "arm,vexpress-legacy"))
> > iotable_init(v2m_io_desc_legacy);
> > else (of_flat_dt_is_compatible(node, "arm,vexpress-rs1"))
> > iotable_init(v2m_io_desc_rs1);
> > else
> > panic();
> > }
> >
> > Neither of them seem particularly appealing... ;-)
>
> But I think both ways would be acceptable in the end. It's not a lot
> of extra code either way. In the second case, I would probably have
> the legacy case as a special variant of the map_io function and have
> all others be the default instead of falling back to panic though.
Ok, I'll go (roughly) that way.
> > In my case it's sysreg and sysctl. There are two more users of static
> > mappings: timer01 and timer23, but they could at some point do ioremap()
> > on their own (especially with Nico's changes).
>
> Well, I think with Nico's cahnges, you /can/ actually do ioremap for
> areas that have been mapped through the iotable before kmalloc is up.
> IIRC, omap does this for a number of peripherals.
>
> It's a bit of a hack, but I think it's much better than taking hardcoded
> addresses.
Yes, I was thinking about that last night. If you think it's acceptable
I'll do this (killing MMIO_P2V on the way ;-)
> With the combination of the points mentioned above, you should be
> able to do:
>
> - map the entire I/O area in map_io(), depending on the board
> - have an __iomem pointer for the sysreg
> - populate that pointer using of_iomap from the device tree address
> before you first access it.
>
> Do you think that would work?
Yes, I suppose so. The last bit (getting the offset from DT) will be a
little ugly, I think, but let's wait till I get some code done.
Cheers!
Pawe?
^ permalink raw reply [flat|nested] 15+ messages in thread
* DT vs ARM static mappings
2011-09-21 9:41 ` Pawel Moll
@ 2011-09-21 9:59 ` Dave Martin
2011-09-21 10:02 ` Pawel Moll
0 siblings, 1 reply; 15+ messages in thread
From: Dave Martin @ 2011-09-21 9:59 UTC (permalink / raw)
To: linux-arm-kernel
On Wed, Sep 21, 2011 at 10:41:49AM +0100, Pawel Moll wrote:
> > > 2. Single DT_MACHINE_START matching (the most generic) "arm,vexpress"
> > > and doing (rougly) this in v2m_map_io:
> > >
> > > of_scan_flat_dt(v2m_dt_iotable_init, NULL);
> > >
> > > v2m_dt_iotable_init(...)
> > > {
> > > if (depth != 0)
> > > return 0;
> > > if (of_flat_dt_is_compatible(node, "arm,vexpress-legacy"))
> > > iotable_init(v2m_io_desc_legacy);
> > > else (of_flat_dt_is_compatible(node, "arm,vexpress-rs1"))
> > > iotable_init(v2m_io_desc_rs1);
> > > else
> > > panic();
> > > }
> > >
> > > Neither of them seem particularly appealing... ;-)
> >
> > But I think both ways would be acceptable in the end. It's not a lot
> > of extra code either way. In the second case, I would probably have
> > the legacy case as a special variant of the map_io function and have
> > all others be the default instead of falling back to panic though.
>
> Ok, I'll go (roughly) that way.
>
> > > In my case it's sysreg and sysctl. There are two more users of static
> > > mappings: timer01 and timer23, but they could at some point do ioremap()
> > > on their own (especially with Nico's changes).
> >
> > Well, I think with Nico's cahnges, you /can/ actually do ioremap for
> > areas that have been mapped through the iotable before kmalloc is up.
> > IIRC, omap does this for a number of peripherals.
> >
> > It's a bit of a hack, but I think it's much better than taking hardcoded
> > addresses.
>
> Yes, I was thinking about that last night. If you think it's acceptable
> I'll do this (killing MMIO_P2V on the way ;-)
>
> > With the combination of the points mentioned above, you should be
> > able to do:
> >
> > - map the entire I/O area in map_io(), depending on the board
> > - have an __iomem pointer for the sysreg
> > - populate that pointer using of_iomap from the device tree address
> > before you first access it.
> >
> > Do you think that would work?
>
> Yes, I suppose so. The last bit (getting the offset from DT) will be a
> little ugly, I think, but let's wait till I get some code done.
I won't attempt to modify the rest of the patch yet, but we can roll
changes in when you've decided on a way forward.
Alternatively, the requisite changes can be done as patches on top of
the basic patch -- since the initial patch doesn't attempt to support
multiple core tiles anyway.
Cheers
---Dave
^ permalink raw reply [flat|nested] 15+ messages in thread
* DT vs ARM static mappings
2011-09-21 9:59 ` Dave Martin
@ 2011-09-21 10:02 ` Pawel Moll
0 siblings, 0 replies; 15+ messages in thread
From: Pawel Moll @ 2011-09-21 10:02 UTC (permalink / raw)
To: linux-arm-kernel
> I won't attempt to modify the rest of the patch yet, but we can roll
> changes in when you've decided on a way forward.
>
> Alternatively, the requisite changes can be done as patches on top of
> the basic patch -- since the initial patch doesn't attempt to support
> multiple core tiles anyway.
Sure thing - I'll work on top of your patch.
Pawe?
^ permalink raw reply [flat|nested] 15+ messages in thread
* DT vs ARM static mappings
2011-09-20 11:51 DT vs ARM static mappings Pawel Moll
2011-09-20 12:58 ` Rob Herring
@ 2011-09-21 17:49 ` Nicolas Pitre
2011-09-22 13:04 ` Pawel Moll
1 sibling, 1 reply; 15+ messages in thread
From: Nicolas Pitre @ 2011-09-21 17:49 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, 20 Sep 2011, Pawel Moll wrote:
> ARM machine description contains a "map_io" method, which is used to
> create static memory mappings (using iotable_init() function) for things
> like peripherals or SRAMs. At least that's the theory, because most of
> the platforms are doing much more stuff there, like clocking/GPIOs/UARTs
> initialization, hardware probing etc.
No, most of them don't. Maybe a few cases do for historical reasons,
but there are other hooks now to link probing and initialization code
to.
The static mappings should be just that: static. Most things should be
dynamically mapped instead. With the series I'm working on, everybody
will get the benefit of a static mapping when one is available even if
the dynamic mapping interface like ioremap() is used. So having a bunch
of static mappings is not bad, especially if they are easy. But you
should defer as much hardware probing as possible after the memory is
initialized and the standard interfaces are available, keeping reliance
on direct access to static mappings as small as possible.
> Now the Versatile Express platform: it consists of a motherboard with a
> set of peripherals and a processor daughterboard (core tile), both
> connected via a static memory bus, which is mapped into processor's
> physical address space. The motherboard can be shared between different
> types of the tiles (eg. A9, A5, A15 etc.). The present one is probed byt
> he motherboard firmware and exposed in "system registers".
>
> Everything is fine so far. The interesting part starts here:
>
> http://infocenter.arm.com/help/topic/com.arm.doc.dui0447e/CACIHGFE.html
>
> In brief, depending on the configuration, the system can have one of
> two, totally different, memory maps (please, do spare me the "but why
> did they do that" comments - not my idea nor decision, I just have to
> live with this ;-), depending on the core tile being used.
>
> In result, the static mapping as defined currently in
> arch/arm/mach-vexpress/v2m.c for A9 variant:
>
> #define V2M_PA_CS7 0x10000000
>
> static struct map_desc v2m_io_desc[] __initdata = {
> {
> .virtual = __MMIO_P2V(V2M_PA_CS7),
> .pfn = __phys_to_pfn(V2M_PA_CS7),
> .length = SZ_128K,
> .type = MT_DEVICE,
> },
> };
>
> is no longer valid for A5/A15. It would rather look like this:
>
> #define V2M_PA_CS3 0x1c000000
>
> static struct map_desc v2m_io_desc[] __initdata = {
> {
> .virtual = __MMIO_P2V(V2M_PA_CS3),
> .pfn = __phys_to_pfn(V2M_PA_CS3),
> .length = SZ_2M,
> .type = MT_DEVICE,
> },
> };
>
> Not only the peripherals base address is changed but also "internal"
> alignment, thus offsets to peripherals. Some of them are not being
> ioremap()ed, but directly used via the static mapping and MMIO_P2V macro
> (like "readl(MMIO_P2V(V2M_SYS_PROCID0))" in v2m_populate_ct_desc(void)
> function). For example, these two:
>
> #define V2M_SYSREGS (V2M_PA_CS7 + 0x00000000)
> #define V2M_SYSCTL (V2M_PA_CS7 + 0x00001000)
>
> would have to become:
>
> #define V2M_SYSREGS (V2M_PA_CS3 + 0x00010000)
> #define V2M_SYSCTL (V2M_PA_CS3 + 0x00020000)
Your best bet would probably consist of keeping the virtual address
constant while the physical address is variable. Adjusting the .pfn
field in the v2m_io_desc table right before calling iotable_init()
should be fine. Alternatively you could have two such tables and select
the right one at run time. The io_p2v macro doesn't make any sense
anymore in that context so it should be eliminated, and keeping only a
minimum set of fixed virtual addresses for the peripherals that can't
wait until ioremap is available should be fine.
Of course you should use the largest alignment for the same peripheral
mapping.
[...]
> To my mind it looked like the whole mechanism was not flexible enough,
> so I wanted to explore other options...
>
> The obvious one was to describe the required static mapping in the DTS.
> I don't like this idea, though. It can hardly be called "hardware
> description". Besides, what node would carry such data? "chosen"?
> Hardly...
>
> Would it contain a "regs" property with the physical address and
> "virtual-reg" with the virtual one? Again, doesn't sound right to me
> (especially the virtual bit, however the virtual address could be common
> between different variants and be defined in the board support code, not
> the DTS).
That's what I'm suggesting: keep the virtual addresses constant, and
adjust the static mapping's physical address accordingly. But never
should virtual addresses be part of DT as this is just an implementation
detail.
And if static mappings are a problem, then try to live without them as
much as possible. Again there is no reason you should be doing too much
hardware probing at .map_io time.
Nicolas
^ permalink raw reply [flat|nested] 15+ messages in thread
* DT vs ARM static mappings
2011-09-21 17:49 ` Nicolas Pitre
@ 2011-09-22 13:04 ` Pawel Moll
2011-09-22 13:13 ` Russell King - ARM Linux
0 siblings, 1 reply; 15+ messages in thread
From: Pawel Moll @ 2011-09-22 13:04 UTC (permalink / raw)
To: linux-arm-kernel
> > ARM machine description contains a "map_io" method, which is used to
> > create static memory mappings (using iotable_init() function) for things
> > like peripherals or SRAMs. At least that's the theory, because most of
> > the platforms are doing much more stuff there, like clocking/GPIOs/UARTs
> > initialization, hardware probing etc.
>
> No, most of them don't. Maybe a few cases do for historical reasons,
> but there are other hooks now to link probing and initialization code
> to.
Ok, what I did was grepping for all .map_io-s. Then I sorted the list
and had a look at first 100 and about 50% of them were doing more than
just creating mappings.
Never mind - I'll rephrase myself to "many" instead of "most" :-)
> The static mappings should be just that: static. Most things should be
> dynamically mapped instead. With the series I'm working on, everybody
> will get the benefit of a static mapping when one is available even if
> the dynamic mapping interface like ioremap() is used. So having a bunch
> of static mappings is not bad, especially if they are easy. But you
> should defer as much hardware probing as possible after the memory is
> initialized and the standard interfaces are available, keeping reliance
> on direct access to static mappings as small as possible.
You won't get any argument from me here - my task would be easier
without the additional things happening in map_io...
> Your best bet would probably consist of keeping the virtual address
> constant while the physical address is variable. Adjusting the .pfn
> field in the v2m_io_desc table right before calling iotable_init()
> should be fine. Alternatively you could have two such tables and select
> the right one at run time. The io_p2v macro doesn't make any sense
> anymore in that context so it should be eliminated, and keeping only a
> minimum set of fixed virtual addresses for the peripherals that can't
> wait until ioremap is available should be fine.
Yep, that's (roughly) what my code is doing now. There is some hackery
involved (manual operations on pointers) that will disappear with your
changes.
And MMIO_P2V macro is dying - motherboard code is not using it any more,
the tile code will stop using it next week.
> And if static mappings are a problem, then try to live without them as
> much as possible. Again there is no reason you should be doing too much
> hardware probing at .map_io time.
Current implementation is doing very little (just probing tile ID and
calling tile's private map_io) but it's enough to be a pain in the neck.
Anyway, patch (on top of Dave's initial support) to follow soon.
Cheers!
Pawe?
^ permalink raw reply [flat|nested] 15+ messages in thread
* DT vs ARM static mappings
2011-09-22 13:04 ` Pawel Moll
@ 2011-09-22 13:13 ` Russell King - ARM Linux
2011-09-22 13:45 ` Pawel Moll
0 siblings, 1 reply; 15+ messages in thread
From: Russell King - ARM Linux @ 2011-09-22 13:13 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Sep 22, 2011 at 02:04:56PM +0100, Pawel Moll wrote:
> > > ARM machine description contains a "map_io" method, which is used to
> > > create static memory mappings (using iotable_init() function) for things
> > > like peripherals or SRAMs. At least that's the theory, because most of
> > > the platforms are doing much more stuff there, like clocking/GPIOs/UARTs
> > > initialization, hardware probing etc.
> >
> > No, most of them don't. Maybe a few cases do for historical reasons,
> > but there are other hooks now to link probing and initialization code
> > to.
>
> Ok, what I did was grepping for all .map_io-s. Then I sorted the list
> and had a look at first 100 and about 50% of them were doing more than
> just creating mappings.
The answer to that is: they shouldn't be now that we have the init_early
hook. The only remainder for .map_io is where platforms make run-time
decisions about what to map based on some register value somewhere
(eg, Assabet vs Assabet+Neponset).
I do have a large patch series floating around in my git tree which tries
to clean up to all those map_io functions - the biggest stumbling block
to them is the Samsung stuff being indirected through its own tables.
Of course, with all the changes to .boot_params etc, the patches no longer
apply to current kernels.
^ permalink raw reply [flat|nested] 15+ messages in thread
* DT vs ARM static mappings
2011-09-22 13:13 ` Russell King - ARM Linux
@ 2011-09-22 13:45 ` Pawel Moll
0 siblings, 0 replies; 15+ messages in thread
From: Pawel Moll @ 2011-09-22 13:45 UTC (permalink / raw)
To: linux-arm-kernel
> > Ok, what I did was grepping for all .map_io-s. Then I sorted the list
> > and had a look at first 100 and about 50% of them were doing more than
> > just creating mappings.
>
> The answer to that is: they shouldn't be now that we have the init_early
> hook. The only remainder for .map_io is where platforms make run-time
> decisions about what to map based on some register value somewhere
> (eg, Assabet vs Assabet+Neponset).
>
> I do have a large patch series floating around in my git tree which tries
> to clean up to all those map_io functions - the biggest stumbling block
> to them is the Samsung stuff being indirected through its own tables.
Awesome. I'll work with an assumption that future map_io-s will only
create static mappings and nothing more then.
Cheers!
Pawe?
^ permalink raw reply [flat|nested] 15+ messages in thread
* DT vs ARM static mappings
2011-09-20 19:28 ` Arnd Bergmann
2011-09-21 9:41 ` Pawel Moll
@ 2011-09-22 16:23 ` Pawel Moll
2011-09-23 15:45 ` Arnd Bergmann
1 sibling, 1 reply; 15+ messages in thread
From: Pawel Moll @ 2011-09-22 16:23 UTC (permalink / raw)
To: linux-arm-kernel
> - map the entire I/O area in map_io(), depending on the board
> - have an __iomem pointer for the sysreg
> - populate that pointer using of_iomap from the device tree address
> before you first access it.
Ok, so what I came with is below... It's based more-or-less on top of
Dave's patch (it's just a development snapshot, don't treat it as a
final proposal).
Executive summary:
* I have second map_desc with pfn for RS1 memory map, but using the same
virtual address as the legacy one. The legacy one is used if root of the
tree is compatible with "arm,vexpress-legacy".
* The devices I need to use in v2m.c have aliases in DTS so I can find
their offsets in the flat tree (the *_find_node_by_alias() function is
rather generic and could be moved to drivers/of/fdt.c if you think it
would be useful for others).
* There are no more users of MMIO_P2V in v2m.c, next thing I will do is
the same in core tile; then the macro can be killed. Once this happens
the virtual address currently taken from __MMIO_P2V(V2M_PA_CS7) will be
replaced by some kind of "#define V2M_PERIPH_BASE 0xf8000000".
* Once Nico's changes regarding static maps are in, the manual pointer
operations in v2m_dt_map_io can be replaced with neat ioremap()-s.
All feedback appreciated, cheers!
Pawe?
diff --git a/arch/arm/boot/dts/vexpress-v2m-legacy.dtsi b/arch/arm/boot/dts/vexpress-v2m-legacy.dtsi
index cb18052..ec40e5c 100644
--- a/arch/arm/boot/dts/vexpress-v2m-legacy.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m-legacy.dtsi
@@ -9,6 +9,10 @@
serial3 = &uart3;
i2c0 = &i2c0;
i2c1 = &i2c1;
+ timer01 = &timer01;
+ timer23 = &timer23;
+ sysreg = &sysreg;
+ sysctl = &sysctl;
};
motherboard {
@@ -48,6 +52,16 @@
#size-cells = <1>;
ranges = <0 7 0 0x20000>;
+ sysreg: sysreg at 00000 {
+ compatible = "arm,vexpress-sysreg";
+ reg = <0x00000 0x1000>;
+ };
+
+ sysctl: sysctl at 01000 {
+ compatible = "arm,sp810";
+ reg = <0x01000 0x1000>;
+ };
+
// PCI-E I2C bus
i2c0: i2c at 02000 {
compatible = "arm,versatile-i2c";
@@ -116,6 +130,16 @@
interrupts = <0>;
};
+ timer01: timer at 11000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x11000 0x1000>;
+ };
+
+ timer23: timer at 12000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x12000 0x1000>;
+ };
+
// DVI I2C bus
i2c1: i2c at 16000 {
compatible = "arm,versatile-i2c";
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
index 5fc4871..dadaae1 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca9.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
@@ -6,7 +6,7 @@
/ {
model = "ARM Versatile Express";
- compatible = "arm,vexpress-v2p-ca9", "arm,vexpress";
+ compatible = "arm,vexpress-v2p-ca9", "arm,vexpress-legacy", "arm,vexpress";
interrupt-parent = <&intc>;
memory {
diff --git a/arch/arm/include/asm/hardware/arm_timer.h b/arch/arm/include/asm/hardware/arm_timer.h
index c0f4e7b..d6030ff 100644
--- a/arch/arm/include/asm/hardware/arm_timer.h
+++ b/arch/arm/include/asm/hardware/arm_timer.h
@@ -9,7 +9,12 @@
*
* Integrator AP has 16-bit timers, Integrator CP, Versatile and Realview
* can have 16-bit or 32-bit selectable via a bit in the control register.
+ *
+ * Every SP804 contains two identical timers.
*/
+#define TIMER_1_BASE 0x00
+#define TIMER_2_BASE 0x20
+
#define TIMER_LOAD 0x00 /* ACVR rw */
#define TIMER_VALUE 0x04 /* ACVR ro */
#define TIMER_CTRL 0x08 /* ACVR rw */
diff --git a/arch/arm/mach-vexpress/include/mach/motherboard.h b/arch/arm/mach-vexpress/include/mach/motherboard.h
index 0a3a375..0b42b96 100644
--- a/arch/arm/mach-vexpress/include/mach/motherboard.h
+++ b/arch/arm/mach-vexpress/include/mach/motherboard.h
@@ -39,34 +39,27 @@
#define V2M_CF (V2M_PA_CS7 + 0x0001a000)
#define V2M_CLCD (V2M_PA_CS7 + 0x0001f000)
-#define V2M_SYS_ID (V2M_SYSREGS + 0x000)
-#define V2M_SYS_SW (V2M_SYSREGS + 0x004)
-#define V2M_SYS_LED (V2M_SYSREGS + 0x008)
-#define V2M_SYS_100HZ (V2M_SYSREGS + 0x024)
-#define V2M_SYS_FLAGS (V2M_SYSREGS + 0x030)
-#define V2M_SYS_FLAGSSET (V2M_SYSREGS + 0x030)
-#define V2M_SYS_FLAGSCLR (V2M_SYSREGS + 0x034)
-#define V2M_SYS_NVFLAGS (V2M_SYSREGS + 0x038)
-#define V2M_SYS_NVFLAGSSET (V2M_SYSREGS + 0x038)
-#define V2M_SYS_NVFLAGSCLR (V2M_SYSREGS + 0x03c)
-#define V2M_SYS_MCI (V2M_SYSREGS + 0x048)
-#define V2M_SYS_FLASH (V2M_SYSREGS + 0x03c)
-#define V2M_SYS_CFGSW (V2M_SYSREGS + 0x058)
-#define V2M_SYS_24MHZ (V2M_SYSREGS + 0x05c)
-#define V2M_SYS_MISC (V2M_SYSREGS + 0x060)
-#define V2M_SYS_DMA (V2M_SYSREGS + 0x064)
-#define V2M_SYS_PROCID0 (V2M_SYSREGS + 0x084)
-#define V2M_SYS_PROCID1 (V2M_SYSREGS + 0x088)
-#define V2M_SYS_CFGDATA (V2M_SYSREGS + 0x0a0)
-#define V2M_SYS_CFGCTRL (V2M_SYSREGS + 0x0a4)
-#define V2M_SYS_CFGSTAT (V2M_SYSREGS + 0x0a8)
-
-#define V2M_TIMER0 (V2M_TIMER01 + 0x000)
-#define V2M_TIMER1 (V2M_TIMER01 + 0x020)
-
-#define V2M_TIMER2 (V2M_TIMER23 + 0x000)
-#define V2M_TIMER3 (V2M_TIMER23 + 0x020)
-
+#define V2M_SYS_ID 0x000
+#define V2M_SYS_SW 0x004
+#define V2M_SYS_LED 0x008
+#define V2M_SYS_100HZ 0x024
+#define V2M_SYS_FLAGS 0x030
+#define V2M_SYS_FLAGSSET 0x030
+#define V2M_SYS_FLAGSCLR 0x034
+#define V2M_SYS_NVFLAGS 0x038
+#define V2M_SYS_NVFLAGSSET 0x038
+#define V2M_SYS_NVFLAGSCLR 0x03c
+#define V2M_SYS_MCI 0x048
+#define V2M_SYS_FLASH 0x03c
+#define V2M_SYS_CFGSW 0x058
+#define V2M_SYS_24MHZ 0x05c
+#define V2M_SYS_MISC 0x060
+#define V2M_SYS_DMA 0x064
+#define V2M_SYS_PROCID0 0x084
+#define V2M_SYS_PROCID1 0x088
+#define V2M_SYS_CFGDATA 0x0a0
+#define V2M_SYS_CFGCTRL 0x0a4
+#define V2M_SYS_CFGSTAT 0x0a8
/*
* Interrupts. Those in {} are for AMBA devices
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index ed00d52..16e4006 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -6,6 +6,8 @@
#include <linux/amba/mmci.h>
#include <linux/io.h>
#include <linux/init.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
@@ -33,13 +35,14 @@
#include "core.h"
+/* Legacy memory map values for backward compatibility */
#define V2M_PA_CS0 0x40000000
#define V2M_PA_CS1 0x44000000
#define V2M_PA_CS2 0x48000000
#define V2M_PA_CS3 0x4c000000
#define V2M_PA_CS7 0x10000000
-static struct map_desc v2m_io_desc[] __initdata = {
+static struct map_desc v2m_legacy_io_desc[] __initdata = {
{
.virtual = __MMIO_P2V(V2M_PA_CS7),
.pfn = __phys_to_pfn(V2M_PA_CS7),
@@ -48,21 +51,36 @@ static struct map_desc v2m_io_desc[] __initdata = {
},
};
+static struct map_desc v2m_rs1_io_desc[] __initdata = {
+ {
+ .virtual = __MMIO_P2V(V2M_PA_CS7),
+ .pfn = __phys_to_pfn(0x1c000000),
+ .length = SZ_2M,
+ .type = MT_DEVICE,
+ },
+};
+
+static void __iomem *v2m_sysreg_base;
+static void __iomem *v2m_sysctl_base;
+static void __iomem *v2m_timer01_base;
+
+
+
static void __init v2m_timer_init(void)
{
u32 scctrl;
/* Select 1MHz TIMCLK as the reference clock for SP804 timers */
- scctrl = readl(MMIO_P2V(V2M_SYSCTL + SCCTRL));
+ scctrl = readl(v2m_sysctl_base + SCCTRL);
scctrl |= SCCTRL_TIMEREN0SEL_TIMCLK;
scctrl |= SCCTRL_TIMEREN1SEL_TIMCLK;
- writel(scctrl, MMIO_P2V(V2M_SYSCTL + SCCTRL));
+ writel(scctrl, v2m_sysctl_base + SCCTRL);
- writel(0, MMIO_P2V(V2M_TIMER0) + TIMER_CTRL);
- writel(0, MMIO_P2V(V2M_TIMER1) + TIMER_CTRL);
+ writel(0, v2m_timer01_base + TIMER_1_BASE + TIMER_CTRL);
+ writel(0, v2m_timer01_base + TIMER_2_BASE + TIMER_CTRL);
- sp804_clocksource_init(MMIO_P2V(V2M_TIMER1), "v2m-timer1");
- sp804_clockevents_init(MMIO_P2V(V2M_TIMER0), IRQ_V2M_TIMER0,
+ sp804_clocksource_init(v2m_timer01_base + TIMER_1_BASE, "v2m-timer1");
+ sp804_clockevents_init(v2m_timer01_base + TIMER_2_BASE, IRQ_V2M_TIMER0,
"v2m-timer0");
}
@@ -83,14 +101,14 @@ int v2m_cfg_write(u32 devfn, u32 data)
devfn |= SYS_CFG_START | SYS_CFG_WRITE;
spin_lock(&v2m_cfg_lock);
- val = readl(MMIO_P2V(V2M_SYS_CFGSTAT));
- writel(val & ~SYS_CFG_COMPLETE, MMIO_P2V(V2M_SYS_CFGSTAT));
+ val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
+ writel(val & ~SYS_CFG_COMPLETE, v2m_sysreg_base + V2M_SYS_CFGSTAT);
- writel(data, MMIO_P2V(V2M_SYS_CFGDATA));
- writel(devfn, MMIO_P2V(V2M_SYS_CFGCTRL));
+ writel(data, v2m_sysreg_base + V2M_SYS_CFGDATA);
+ writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL);
do {
- val = readl(MMIO_P2V(V2M_SYS_CFGSTAT));
+ val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
} while (val == 0);
spin_unlock(&v2m_cfg_lock);
@@ -104,17 +122,17 @@ int v2m_cfg_read(u32 devfn, u32 *data)
devfn |= SYS_CFG_START;
spin_lock(&v2m_cfg_lock);
- writel(0, MMIO_P2V(V2M_SYS_CFGSTAT));
- writel(devfn, MMIO_P2V(V2M_SYS_CFGCTRL));
+ writel(0, v2m_sysreg_base + V2M_SYS_CFGSTAT);
+ writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL);
mb();
do {
cpu_relax();
- val = readl(MMIO_P2V(V2M_SYS_CFGSTAT));
+ val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
} while (val == 0);
- *data = readl(MMIO_P2V(V2M_SYS_CFGDATA));
+ *data = readl(v2m_sysreg_base + V2M_SYS_CFGDATA);
spin_unlock(&v2m_cfg_lock);
return !!(val & SYS_CFG_ERR);
@@ -205,7 +223,7 @@ static struct platform_device v2m_usb_device = {
static void v2m_flash_set_vpp(struct platform_device *pdev, int on)
{
- writel(on != 0, MMIO_P2V(V2M_SYS_FLASH));
+ writel(on != 0, v2m_sysreg_base + V2M_SYS_FLASH);
}
static struct physmap_flash_data v2m_flash_data = {
@@ -259,7 +277,7 @@ static struct platform_device v2m_cf_device = {
static unsigned int v2m_mmci_status(struct device *dev)
{
- return readl(MMIO_P2V(V2M_SYS_MCI)) & (1 << 0);
+ return readl(v2m_sysreg_base + V2M_SYS_MCI) & (1 << 0);
}
static struct mmci_platform_data v2m_mmci_data = {
@@ -372,7 +390,7 @@ static void __init v2m_init_early(void)
{
ct_desc->init_early();
clkdev_add_table(v2m_lookups, ARRAY_SIZE(v2m_lookups));
- versatile_sched_clock_init(MMIO_P2V(V2M_SYS_24MHZ), 24000000);
+ versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
}
static void v2m_power_off(void)
@@ -401,7 +419,8 @@ static void __init v2m_populate_ct_desc(void)
u32 current_tile_id;
ct_desc = NULL;
- current_tile_id = readl(MMIO_P2V(V2M_SYS_PROCID0)) & V2M_CT_ID_MASK;
+ current_tile_id = readl(v2m_sysreg_base + V2M_SYS_PROCID0)
+ & V2M_CT_ID_MASK;
for (i = 0; i < ARRAY_SIZE(ct_descs) && !ct_desc; ++i)
if (ct_descs[i]->id == current_tile_id)
@@ -414,7 +433,10 @@ static void __init v2m_populate_ct_desc(void)
static void __init v2m_map_io(void)
{
- iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
+ iotable_init(v2m_legacy_io_desc, ARRAY_SIZE(v2m_legacy_io_desc));
+ v2m_sysreg_base = MMIO_P2V(V2M_SYSREGS);
+ v2m_sysctl_base = MMIO_P2V(V2M_SYSCTL);
+ v2m_timer01_base = MMIO_P2V(V2M_TIMER01);
v2m_populate_ct_desc();
ct_desc->map_io();
}
@@ -472,6 +494,135 @@ struct of_dev_auxdata v2m_dt_auxdata_lookup[] __initdata = {
{}
};
+struct v2m_dt_find_alias_state {
+ const char *alias;
+ unsigned long node;
+ const char *path;
+ int depth;
+ int token_len;
+
+};
+
+static int __init v2m_dt_scan_path(unsigned long node,
+ const char *uname, int depth, void *data)
+{
+ struct v2m_dt_find_alias_state *state = data;
+
+ pr_debug("%s: uname='%s', depth=%d, state->path='%s', state->depth=%d,"
+ " state->token_len=%d\n", __func__, uname, depth,
+ state->path, state->depth, state->token_len);
+
+ /* If the depth decreases, we didn't find the path */
+ if (depth < state->depth)
+ return -ENOENT;
+
+ /* Check if path ~= /^uname[\/\0]/ */
+ if (strncmp(state->path, uname, state->token_len) == 0 &&
+ uname[state->token_len] == 0) {
+ const char *slash;
+
+ state->depth++;
+ state->path += state->token_len; /* Next token */
+ if (*state->path == 0) { /* All path tokens processed? */
+ state->node = node;
+ return 1; /* Success! */
+ }
+ BUG_ON(*state->path != '/');
+ state->path++; /* Skip leading slash */
+ slash = strchr(state->path, '/');
+ if (!slash)
+ state->token_len = strlen(state->path);
+ else
+ state->token_len = slash - state->path;
+ }
+
+ return 0;
+}
+
+static int __init v2m_dt_scan_alias(unsigned long node,
+ const char *uname, int depth, void *data)
+{
+ int res;
+ struct v2m_dt_find_alias_state *state = data;
+
+ if (depth != 1 || strcmp(uname, "aliases") != 0)
+ return 0;
+
+ state->path = of_get_flat_dt_prop(node, state->alias, NULL);
+ if (!state->path)
+ return -ENXIO;
+ if (*state->path != '/')
+ return -EFAULT;
+
+ state->token_len = 0; /* Root node has no name */
+ res = of_scan_flat_dt(v2m_dt_scan_path, state);
+ if (res == 0) /* Whole tree scanned, no path found */
+ res = -ENOENT;
+
+ return res;
+}
+
+static int __init v2m_dt_find_node_by_alias(const char *alias,
+ unsigned long *node)
+{
+ int err;
+ struct v2m_dt_find_alias_state state = {
+ .alias = alias,
+ };
+
+ err = of_scan_flat_dt(v2m_dt_scan_alias, &state);
+
+ if (err > 0)
+ *node = state.node;
+
+ return err;
+}
+
+static unsigned long __init v2m_dt_periph_offset(const char *alias)
+{
+ unsigned long node;
+ __be32 *reg;
+ unsigned long len;
+ unsigned long offset;
+
+ if (v2m_dt_find_node_by_alias(alias, &node) <= 0)
+ panic("%s(): Can't get offset for '%s'!\n", __func__, alias);
+
+ reg = of_get_flat_dt_prop(node, "reg", &len);
+ if (!reg)
+ panic("%s(): Can't get reg property for '%s'!\n",
+ __func__, alias);
+
+ return be32_to_cpup(reg);
+}
+
+static void __init v2m_dt_map_io(void)
+{
+ void __iomem *periph_base;
+
+ if (of_flat_dt_is_compatible(of_get_flat_dt_root(),
+ "arm,vexpress-legacy")) {
+ pr_info("v2m: Legacy memory map.\n");
+ iotable_init(v2m_legacy_io_desc,
+ ARRAY_SIZE(v2m_legacy_io_desc));
+ /* Won't be needed once we can call ioremap() in map_io */
+ periph_base = (void __iomem *)v2m_legacy_io_desc[0].virtual;
+ } else {
+ printk("v2m: RS1 memory map.\n");
+ iotable_init(v2m_rs1_io_desc,
+ ARRAY_SIZE(v2m_rs1_io_desc));
+ /* Won't be needed once we can call ioremap() in map_io */
+ periph_base = (void __iomem *)v2m_legacy_io_desc[0].virtual;
+ }
+
+ v2m_sysreg_base = periph_base + v2m_dt_periph_offset("sysreg");
+ v2m_sysctl_base = periph_base + v2m_dt_periph_offset("sysctl");
+ v2m_timer01_base = periph_base + v2m_dt_periph_offset("timer01");
+
+ v2m_populate_ct_desc();
+ ct_desc->map_io();
+}
+
static void __init v2m_dt_init(void)
{
of_platform_populate(NULL, of_default_bus_match_table,
@@ -489,7 +640,7 @@ static const char *v2m_dt_match[] __initconst = {
};
DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express")
- .map_io = v2m_map_io,
+ .map_io = v2m_dt_map_io,
.init_early = v2m_init_early,
.init_irq = v2m_init_irq,
.timer = &v2m_timer,
^ permalink raw reply related [flat|nested] 15+ messages in thread
* DT vs ARM static mappings
2011-09-22 16:23 ` Pawel Moll
@ 2011-09-23 15:45 ` Arnd Bergmann
0 siblings, 0 replies; 15+ messages in thread
From: Arnd Bergmann @ 2011-09-23 15:45 UTC (permalink / raw)
To: linux-arm-kernel
On Thursday 22 September 2011, Pawel Moll wrote:
> Executive summary:
>
> * I have second map_desc with pfn for RS1 memory map, but using the same
> virtual address as the legacy one. The legacy one is used if root of the
> tree is compatible with "arm,vexpress-legacy".
>
> * The devices I need to use in v2m.c have aliases in DTS so I can find
> their offsets in the flat tree (the *_find_node_by_alias() function is
> rather generic and could be moved to drivers/of/fdt.c if you think it
> would be useful for others).
>
> * There are no more users of MMIO_P2V in v2m.c, next thing I will do is
> the same in core tile; then the macro can be killed. Once this happens
> the virtual address currently taken from __MMIO_P2V(V2M_PA_CS7) will be
> replaced by some kind of "#define V2M_PERIPH_BASE 0xf8000000".
>
> * Once Nico's changes regarding static maps are in, the manual pointer
> operations in v2m_dt_map_io can be replaced with neat ioremap()-s.
>
> All feedback appreciated, cheers!
Look ok to me. Just a comment on the submission:
Even when you post something for review instead of inclusion, please add
a Signed-off-by: line and a diffstat.
Arnd
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2011-09-23 15:45 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-09-20 11:51 DT vs ARM static mappings Pawel Moll
2011-09-20 12:58 ` Rob Herring
2011-09-20 14:02 ` Pawel Moll
2011-09-20 14:37 ` Rob Herring
2011-09-20 16:16 ` Pawel Moll
2011-09-20 19:28 ` Arnd Bergmann
2011-09-21 9:41 ` Pawel Moll
2011-09-21 9:59 ` Dave Martin
2011-09-21 10:02 ` Pawel Moll
2011-09-22 16:23 ` Pawel Moll
2011-09-23 15:45 ` Arnd Bergmann
2011-09-21 17:49 ` Nicolas Pitre
2011-09-22 13:04 ` Pawel Moll
2011-09-22 13:13 ` Russell King - ARM Linux
2011-09-22 13:45 ` Pawel Moll
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).