From: andrew@lunn.ch (Andrew Lunn)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 9/9] arm: mvebu: switch internal register address at runtime if needed
Date: Wed, 22 May 2013 19:42:58 +0200 [thread overview]
Message-ID: <20130522174258.GO2824@lunn.ch> (raw)
In-Reply-To: <1369132414-18959-10-git-send-email-thomas.petazzoni@free-electrons.com>
On Tue, May 21, 2013 at 12:33:34PM +0200, Thomas Petazzoni wrote:
> On Marvell platforms, the "internal registers" is a window of 1 MB of
> the physical address space that contains all the registers for the
> various peripherals of the SoC (timers, interrupt controllers, GPIO
> controllers, Ethernet, etc.). The base address of this 1 MB window is
> configurable, and this base address is configured using a register
> that is itself part of this window.
>
> All earlier families of Marvell EBU SoCs supported by Linux used
> 0xf1000000 as the base address of the internal registers window. For
> some reason, early versions of the Marvell 370/XP platforms used
> 0xd0000000 as the base address. This base address is set up by the
> bootloader. However, in order to keep as much physical address space
> to address RAM below the 4 GB limit, we had to switch the base address
> of the internal registers window back to 0xf1000000, and we wanted to
> achieve that without breaking existing platforms, where the bootloader
> was initially setting the base address to 0xd0000000. So the kernel is
> responsible for switching to 0xf1000000 when needed.
>
> One particular bit of a CP15 register has been chosen to indicate
> whether we use an old bootloader (setting the address at 0xd0000000)
> or a new bootloader (setting the address at 0xf1000000). In the
> ->map_io() function, when the bit is already set, there is nothing to
> do, we are already using a new bootloader and internal registers are
> at 0xf1000000.
>
> However, when the bit is not set, we do a static mapping of the
> register area that allows to change the internal register address, we
> change this address, and set this bit.
>
> Note that this mechanism also needs cooperation from the earlyprintk
> addruart handler (in arch/arm/include/debug/mvebu.S). This is where
> things get complex: the CP15 bit that has been chosen gets reset to
> zero at the first call to the 'wfi' instruction. So it cannot be used
> during the entire life of the system. Instead, whenever the ->map_io()
> function has switched to the internal register space to the new
> address, it sets a global variable 'mvebu_switched_regs', which the
> earlyprintk reads. If it's true, then the move has already been done
> and there is no need to read the CP15 register. If
> 'mvebu_switched_regs' is false, we are before the register move, so we
> need to read the CP15 bit to find out whether we're being booted from
> an old bootloader (which mapped the register space at 0xd0000000) or a
> new bootloader (which mapped the register space at 0xf1000000).
>
> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> ---
> arch/arm/boot/dts/armada-370-xp.dtsi | 2 +-
> arch/arm/boot/dts/armada-370.dtsi | 2 +-
> arch/arm/include/debug/mvebu.S | 77 +++++++++++++++++++++++--
> arch/arm/mach-mvebu/armada-370-xp.c | 104 ++++++++++++++++++++++++++++++++++
> arch/arm/mach-mvebu/armada-370-xp.h | 2 +-
> 5 files changed, 178 insertions(+), 9 deletions(-)
>
> diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi
> index 96a6bcd..1e7561e 100644
> --- a/arch/arm/boot/dts/armada-370-xp.dtsi
> +++ b/arch/arm/boot/dts/armada-370-xp.dtsi
> @@ -33,7 +33,7 @@
> #size-cells = <1>;
> compatible = "simple-bus";
> interrupt-parent = <&mpic>;
> - ranges = <0 0 0xd0000000 0x100000>;
> + ranges = <0 0 0xf1000000 0x100000>;
>
> internal-regs {
> compatible = "simple-bus";
> diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi
> index b2c1b5a..7ff9c1b 100644
> --- a/arch/arm/boot/dts/armada-370.dtsi
> +++ b/arch/arm/boot/dts/armada-370.dtsi
> @@ -29,7 +29,7 @@
> };
>
> soc {
> - ranges = <0 0xd0000000 0x100000>;
> + ranges = <0 0xf1000000 0x100000>;
> internal-regs {
> system-controller at 18200 {
> compatible = "marvell,armada-370-xp-system-controller";
> diff --git a/arch/arm/include/debug/mvebu.S b/arch/arm/include/debug/mvebu.S
> index df191af..dba702a 100644
> --- a/arch/arm/include/debug/mvebu.S
> +++ b/arch/arm/include/debug/mvebu.S
> @@ -5,20 +5,85 @@
> *
> * Lior Amsalem <alior@marvell.com>
> * Gregory Clement <gregory.clement@free-electrons.com>
> + * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License version 2 as
> * published by the Free Software Foundation.
> */
>
> -#define ARMADA_370_XP_REGS_PHYS_BASE 0xd0000000
> -#define ARMADA_370_XP_REGS_VIRT_BASE 0xfec00000
> +#define ARMADA_370_XP_UART_PHYS_BASE_OLD 0xd0012000
> +#define ARMADA_370_XP_UART_PHYS_BASE_NEW 0xf1012000
> +#define ARMADA_370_XP_UART_VIRT_BASE_OLD 0xfec12000
> +#define ARMADA_370_XP_UART_VIRT_BASE_NEW 0xfebff000
>
> .macro addruart, rp, rv, tmp
> - ldr \rp, =ARMADA_370_XP_REGS_PHYS_BASE
> - ldr \rv, =ARMADA_370_XP_REGS_VIRT_BASE
> - orr \rp, \rp, #0x00012000
> - orr \rv, \rv, #0x00012000
> +
> +#ifndef ZIMAGE
> + /*
> + * This loads the value of mvebu_switched_regs. We need a
> + * little bit of gymnastic here to handle the fact that the
> + * addruart code is duplicated in different places, and called
> + * sometimes with the MMU disabled, sometimes the MMU enabled.
> + *
> + * Notice that when this earlyprintk code is linked into the
> + * kernel decompressor (i.e ZIMAGE is defined), this code isn't
> + * compiled. The reason is because the global mvebu_switched_regs
> + * variable is not available in the decompressor code. At this
> + * early stage, we simply test the CP15 bit (below) to know where
> + * the internal registers are.
> + */
> + adr \rp, addruart_switched_regs_\@
> + ldr \rv, [\rp]
> + sub \rv, \rv, \rp
> + ldr \rp, [\rp, #4]
> + sub \tmp, \rp, \rv
> + ldr \rp, [\tmp, #0]
> + cmp \rp, #0
> +
> + /* If we have already switched, then use the new register
> + address */
> + bne addruart_new_\@
> +#endif
> +
> + /*
> + * We haven't switched the register location, so test the CP15
> + * register bit to find whether we are:
> + * - with an old bootloader setting the base address to
> + * 0xd0000000
> + * - with a new bootloader that has already set the
> + * base address to 0xf1000000
> + * We adapt the physical address returned depending on the
> + * value of this bit, but also the virtual address, because we
> + * can't remap the old physical address and the new physical
> + * address at the same location.
> + */
> + mrc p15, 0, \tmp, c5, c0, 0
> + and \tmp, \tmp, #(1 << 11)
> + cmp \tmp, #0
> + bne addruart_new_\@
> +
> +addruart_old_\@:
> + ldr \rp, =ARMADA_370_XP_UART_PHYS_BASE_OLD
> + ldr \rv, =ARMADA_370_XP_UART_VIRT_BASE_OLD
> + b addruart_out_\@
> +addruart_new_\@:
> + ldr \rp, =ARMADA_370_XP_UART_PHYS_BASE_NEW
> + ldr \rv, =ARMADA_370_XP_UART_VIRT_BASE_NEW
> + b addruart_out_\@
> +
> +#ifndef ZIMAGE
> + /*
> + * Global variable mvebu_switched_regs not visible in the
> + * decompressor code
> + */
> + .align
> +addruart_switched_regs_\@:
> + .long .
> + .long mvebu_switched_regs
> +#endif
> +
> +addruart_out_\@:
> .endm
>
> #define UART_SHIFT 2
> diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c
> index 90cc0e8..c56875e 100644
> --- a/arch/arm/mach-mvebu/armada-370-xp.c
> +++ b/arch/arm/mach-mvebu/armada-370-xp.c
> @@ -29,8 +29,112 @@
> #include "common.h"
> #include "coherency.h"
>
> +/*
> + * Note on the internal register address.
> + *
> + * On Marvell platforms, the "internal registers" is a window of 1 MB
> + * of the physical address space that contains all the registers for
> + * the various peripherals of the SoC (timers, interrupt controllers,
> + * GPIO controllers, Ethernet, etc.). The base address of this 1 MB
> + * window is configurable, and this base address is configured using a
> + * register that is itself part of this window.
> + *
> + * All earlier families of Marvell EBU SoCs supported by Linux used
> + * 0xf1000000 as the base address of the internal registers
> + * window. For some reason, early versions of the Marvell 370/XP
> + * platforms used 0xd0000000 as the base address. This base address is
> + * set up by the bootloader. However, in order to keep as much
> + * physical address space to address RAM below the 4 GB limit, we had
> + * to switch the base address of the internal registers window back to
> + * 0xf1000000, and we wanted to achieve that without breaking existing
> + * platforms, where the bootloader was initially setting the base
> + * address to 0xd0000000. So the kernel is responsible for switching
> + * to 0xf1000000 when needed.
> + *
> + * One particular bit of a CP15 register has been chosen to indicate
> + * whether we use an old bootloader (setting the address at
> + * 0xd0000000) or a new bootloader (setting the address at
> + * 0xf1000000). In the ->map_io() function, when the bit is already
> + * set, there is nothing to do, we are already using a new bootloader
> + * and internal registers are at 0xf1000000.
> + *
> + * However, when the bit is not set, we do a static mapping of the
> + * register area that allows to change the internal register address,
> + * we change this address, and set this bit.
Hi Thomas
Please could you explain this "and set this bit".
If i understand the comment correctly, you are talking about the bit
in CP15. Why is it necessary to set it, since at the next WFI its
going to get cleared. I also don't actually see any code doing the
setting of this bit.
> + *
> + * Note that this mechanism also needs cooperation from the
> + * earlyprintk addruart handler (in arch/arm/include/debug/mvebu.S)
> + * and the early secondary CPU initialization code (in
> + * arch/arm/mach-mvebu/headsmp.S).
> + */
> +
> +#define NEW_INTERNAL_REGS_ADDR 0xf1000000
> +#define OLD_INTERNAL_REGS_ADDR 0xd0000000
> +#define MBUS_OLD_PHYS_ADDR (OLD_INTERNAL_REGS_ADDR + 0x20000)
> +#define MBUS_OLD_VIRT_ADDR 0xfebfe000
> +#define MBUS_INTERNAL_REGS_ADDR 0x80
> +
> +/*
> + * We really want this variable to be part of the .data section,
> + * because it gets accessed by the earlyprintk code before BSS gets
> + * initialized to zero. This variable indicates whether the switch to
> + * the new register has taken place or not. It is needed because the
> + * CP15 bit used by the bootloader to tell the kernel where the
> + * registers are mapped is cleared to 0 at the first 'wfi'
> + * instruction. So we can't use it for the entire life of the system,
> + * and we instead use this boolean to indicate to the earlyprintk code
> + * that the switch has occured and it doesn't need to look at the CP15
> + * bit anymore.
> + */
> +unsigned int __section(.data) mvebu_switched_regs = 0;
> +
> +/*
> + * Detect if we're running an old bootloader that has set the physical
> + * base address of internal registers to 0xd0000000
> + */
> +static int armada_370_xp_has_old_bootloader(void)
> +{
> + u32 val;
> + asm volatile("mrc p15, 0, %0, c5, c0, 0" : "=r"(val));
> + return !(val & BIT(11));
> +}
> +
> static void __init armada_370_xp_map_io(void)
> {
> + if (armada_370_xp_has_old_bootloader()) {
> + struct map_desc desc;
> + void __iomem *mbus = IOMEM(MBUS_OLD_VIRT_ADDR);
> +
> + desc.virtual = MBUS_OLD_VIRT_ADDR;
> + desc.pfn = __phys_to_pfn(MBUS_OLD_PHYS_ADDR);
> + desc.length = PAGE_SIZE;
> + desc.type = MT_DEVICE;
> +
> + /*
> + * Map the area that contains the registers that
> + * allows to change the base address of internal
> + * registers.
> + */
> + iotable_init(&desc, 1);
> +
> + /*
> + * Change the physical base address of the
> + * registers. From now on, and until
> + * debug_ll_io_init() is called below, it is not
> + * possible to do any print, because earlyprintk will
> + * not work.
Is its "not work" or "locks up the CPU as dead as a Dodo?".
Thanks
Andrew
> + */
> + writel(NEW_INTERNAL_REGS_ADDR, mbus + MBUS_INTERNAL_REGS_ADDR);
> + }
> +
> + /*
> + * Either the registers have been switched by the above code,
> + * or the bootloader had already set the register space at the
> + * right location. In both cases, tell the earlyprintk code it
> + * can now use the new location.
> + */
> + mvebu_switched_regs = 1;
> +
> debug_ll_io_init();
> }
>
> diff --git a/arch/arm/mach-mvebu/armada-370-xp.h b/arch/arm/mach-mvebu/armada-370-xp.h
> index 585e147..ff9adc4 100644
> --- a/arch/arm/mach-mvebu/armada-370-xp.h
> +++ b/arch/arm/mach-mvebu/armada-370-xp.h
> @@ -15,7 +15,7 @@
> #ifndef __MACH_ARMADA_370_XP_H
> #define __MACH_ARMADA_370_XP_H
>
> -#define ARMADA_370_XP_REGS_PHYS_BASE 0xd0000000
> +#define ARMADA_370_XP_REGS_PHYS_BASE 0xf1000000
>
> /* These defines can go away once mvebu-mbus has a DT binding */
> #define ARMADA_370_XP_MBUS_WINS_BASE (ARMADA_370_XP_REGS_PHYS_BASE + 0x20000)
> --
> 1.7.9.5
>
next prev parent reply other threads:[~2013-05-22 17:42 UTC|newest]
Thread overview: 91+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-05-21 10:33 [PATCH 0/9] Switch internal registers address to 0xF1 on Armada 370/XP Thomas Petazzoni
2013-05-21 10:33 ` [PATCH 1/9] arm: mvebu: fix length of SATA registers area in .dtsi Thomas Petazzoni
2013-05-21 13:42 ` Jason Cooper
2013-05-21 10:33 ` [PATCH 2/9] arm: mvebu: fix length of Ethernet " Thomas Petazzoni
2013-05-21 13:43 ` Jason Cooper
2013-05-21 10:33 ` [PATCH 3/9] arm: mvebu: mark functions of armada-370-xp.c as static Thomas Petazzoni
2013-05-21 13:45 ` Jason Cooper
2013-05-21 10:33 ` [PATCH 4/9] arm: mvebu: remove dependency of SMP init on static I/O mapping Thomas Petazzoni
2013-05-21 10:33 ` [PATCH 5/9] arm: mvebu: avoid hardcoded virtual address in coherency code Thomas Petazzoni
2013-05-21 10:33 ` [PATCH 6/9] arm: mvebu: move cache and mvebu-mbus initialization later Thomas Petazzoni
2013-05-21 14:16 ` Jason Cooper
2013-05-21 15:37 ` Thomas Petazzoni
2013-05-21 15:43 ` Jason Cooper
2013-05-21 16:10 ` Thomas Petazzoni
2013-05-21 16:37 ` Jason Cooper
2013-05-21 16:44 ` Thomas Petazzoni
2013-05-21 10:33 ` [PATCH 7/9] arm: mvebu: remove hardcoded static I/O mapping Thomas Petazzoni
2013-05-21 10:33 ` [PATCH 8/9] arm: mvebu: don't hardcode a physical address in headsmp.S Thomas Petazzoni
2013-05-21 10:33 ` [PATCH 9/9] arm: mvebu: switch internal register address at runtime if needed Thomas Petazzoni
2013-05-22 13:27 ` Thomas Petazzoni
2013-05-22 14:04 ` Andrew Lunn
2013-05-22 14:16 ` Thomas Petazzoni
2013-05-22 14:17 ` Sebastian Hesselbarth
2013-05-22 17:42 ` Andrew Lunn [this message]
2013-05-22 17:59 ` Thomas Petazzoni
2013-05-22 18:31 ` Andrew Lunn
2013-05-21 19:38 ` [PATCH 0/9] Switch internal registers address to 0xF1 on Armada 370/XP Willy Tarreau
2013-05-21 20:12 ` Thomas Petazzoni
2013-05-21 20:26 ` Willy Tarreau
2013-05-22 10:01 ` Sebastian Hesselbarth
2013-05-22 11:46 ` Greg
2013-05-22 13:43 ` Russell King - ARM Linux
2013-05-22 13:52 ` Thomas Petazzoni
2013-05-22 14:11 ` Arnd Bergmann
2013-05-22 14:17 ` Russell King - ARM Linux
2013-05-22 14:23 ` Sebastian Hesselbarth
2013-05-22 14:33 ` Arnd Bergmann
2013-05-22 14:41 ` Gregory CLEMENT
2013-05-22 15:18 ` Arnd Bergmann
2013-05-22 15:37 ` Gregory CLEMENT
2013-05-22 15:43 ` Arnd Bergmann
2013-05-22 15:56 ` Gregory CLEMENT
2013-05-22 20:30 ` Arnd Bergmann
2013-05-22 15:06 ` Thomas Petazzoni
2013-05-22 15:35 ` Arnd Bergmann
2013-05-22 15:51 ` Andrew Lunn
2013-05-22 16:22 ` Thomas Petazzoni
2013-05-22 20:36 ` Arnd Bergmann
2013-05-23 10:02 ` Thomas Petazzoni
2013-05-23 14:12 ` Arnd Bergmann
2013-05-23 14:47 ` Thomas Petazzoni
2013-05-23 17:39 ` Arnd Bergmann
2013-05-22 16:08 ` Thomas Petazzoni
2013-05-22 16:35 ` Willy Tarreau
2013-05-22 16:42 ` Thomas Petazzoni
2013-05-22 16:49 ` Willy Tarreau
2013-05-22 17:00 ` Thomas Petazzoni
2013-05-22 17:08 ` Willy Tarreau
2013-05-22 17:14 ` Thomas Petazzoni
2013-05-22 20:47 ` Sebastian Hesselbarth
2013-05-22 16:49 ` Jason Cooper
2013-05-22 16:57 ` Thomas Petazzoni
2013-05-22 17:13 ` Jason Cooper
2013-05-22 18:05 ` Thomas Petazzoni
2013-05-22 18:09 ` Jason Cooper
2013-05-22 18:13 ` Thomas Petazzoni
2013-05-22 18:19 ` Jason Gunthorpe
2013-05-22 18:55 ` Andrew Lunn
2013-05-22 19:36 ` Jason Gunthorpe
2013-05-22 20:31 ` Andrew Lunn
2013-05-23 9:53 ` Thomas Petazzoni
2013-05-23 17:27 ` Jason Gunthorpe
2013-05-22 20:40 ` Arnd Bergmann
2013-05-22 21:31 ` Thomas Petazzoni
2013-05-23 5:53 ` Andrew Lunn
2013-05-23 7:53 ` Russell King - ARM Linux
2013-05-23 12:23 ` Thomas Petazzoni
2013-05-23 14:14 ` Arnd Bergmann
2013-05-23 14:50 ` Thomas Petazzoni
2013-05-23 20:26 ` Russell King - ARM Linux
2013-05-23 20:40 ` Arnd Bergmann
2013-05-23 23:09 ` Russell King - ARM Linux
2013-05-23 23:17 ` Thomas Petazzoni
2013-05-23 23:40 ` Russell King - ARM Linux
2013-05-24 10:25 ` Greg
2013-05-24 7:15 ` Arnd Bergmann
2013-05-24 7:43 ` Thomas Petazzoni
2013-05-24 9:16 ` Arnd Bergmann
2013-05-24 7:46 ` Russell King - ARM Linux
2013-05-24 8:07 ` Thomas Petazzoni
2013-05-24 10:57 ` Arnd Bergmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20130522174258.GO2824@lunn.ch \
--to=andrew@lunn.ch \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).