123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- /*
- * Coherency fabric: low level functions
- *
- * Copyright (C) 2012 Marvell
- *
- * Gregory CLEMENT <gregory.clement@free-electrons.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- *
- * This file implements the assembly function to add a CPU to the
- * coherency fabric. This function is called by each of the secondary
- * CPUs during their early boot in an SMP kernel, this why this
- * function have to callable from assembly. It can also be called by a
- * primary CPU from C code during its boot.
- */
- #include <linux/linkage.h>
- #define ARMADA_XP_CFB_CTL_REG_OFFSET 0x0
- #define ARMADA_XP_CFB_CFG_REG_OFFSET 0x4
- #include <asm/assembler.h>
- #include <asm/cp15.h>
- .text
- /*
- * Returns the coherency base address in r1 (r0 is untouched), or 0 if
- * the coherency fabric is not enabled.
- */
- ENTRY(ll_get_coherency_base)
- mrc p15, 0, r1, c1, c0, 0
- tst r1, #CR_M @ Check MMU bit enabled
- bne 1f
- /*
- * MMU is disabled, use the physical address of the coherency
- * base address. However, if the coherency fabric isn't mapped
- * (i.e its virtual address is zero), it means coherency is
- * not enabled, so we return 0.
- */
- ldr r1, =coherency_base
- cmp r1, #0
- beq 2f
- adr r1, 3f
- ldr r3, [r1]
- ldr r1, [r1, r3]
- b 2f
- 1:
- /*
- * MMU is enabled, use the virtual address of the coherency
- * base address.
- */
- ldr r1, =coherency_base
- ldr r1, [r1]
- 2:
- ret lr
- ENDPROC(ll_get_coherency_base)
- /*
- * Returns the coherency CPU mask in r3 (r0 is untouched). This
- * coherency CPU mask can be used with the coherency fabric
- * configuration and control registers. Note that the mask is already
- * endian-swapped as appropriate so that the calling functions do not
- * have to care about endianness issues while accessing the coherency
- * fabric registers
- */
- ENTRY(ll_get_coherency_cpumask)
- mrc 15, 0, r3, cr0, cr0, 5
- and r3, r3, #15
- mov r2, #(1 << 24)
- lsl r3, r2, r3
- ARM_BE8(rev r3, r3)
- ret lr
- ENDPROC(ll_get_coherency_cpumask)
- /*
- * ll_add_cpu_to_smp_group(), ll_enable_coherency() and
- * ll_disable_coherency() use the strex/ldrex instructions while the
- * MMU can be disabled. The Armada XP SoC has an exclusive monitor
- * that tracks transactions to Device and/or SO memory and thanks to
- * that, exclusive transactions are functional even when the MMU is
- * disabled.
- */
- ENTRY(ll_add_cpu_to_smp_group)
- /*
- * As r0 is not modified by ll_get_coherency_base() and
- * ll_get_coherency_cpumask(), we use it to temporarly save lr
- * and avoid it being modified by the branch and link
- * calls. This function is used very early in the secondary
- * CPU boot, and no stack is available at this point.
- */
- mov r0, lr
- bl ll_get_coherency_base
- /* Bail out if the coherency is not enabled */
- cmp r1, #0
- reteq r0
- bl ll_get_coherency_cpumask
- mov lr, r0
- add r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET
- 1:
- ldrex r2, [r0]
- orr r2, r2, r3
- strex r1, r2, [r0]
- cmp r1, #0
- bne 1b
- ret lr
- ENDPROC(ll_add_cpu_to_smp_group)
- ENTRY(ll_enable_coherency)
- /*
- * As r0 is not modified by ll_get_coherency_base() and
- * ll_get_coherency_cpumask(), we use it to temporarly save lr
- * and avoid it being modified by the branch and link
- * calls. This function is used very early in the secondary
- * CPU boot, and no stack is available at this point.
- */
- mov r0, lr
- bl ll_get_coherency_base
- /* Bail out if the coherency is not enabled */
- cmp r1, #0
- reteq r0
- bl ll_get_coherency_cpumask
- mov lr, r0
- add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
- 1:
- ldrex r2, [r0]
- orr r2, r2, r3
- strex r1, r2, [r0]
- cmp r1, #0
- bne 1b
- dsb
- mov r0, #0
- ret lr
- ENDPROC(ll_enable_coherency)
- ENTRY(ll_disable_coherency)
- /*
- * As r0 is not modified by ll_get_coherency_base() and
- * ll_get_coherency_cpumask(), we use it to temporarly save lr
- * and avoid it being modified by the branch and link
- * calls. This function is used very early in the secondary
- * CPU boot, and no stack is available at this point.
- */
- mov r0, lr
- bl ll_get_coherency_base
- /* Bail out if the coherency is not enabled */
- cmp r1, #0
- reteq r0
- bl ll_get_coherency_cpumask
- mov lr, r0
- add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
- 1:
- ldrex r2, [r0]
- bic r2, r2, r3
- strex r1, r2, [r0]
- cmp r1, #0
- bne 1b
- dsb
- ret lr
- ENDPROC(ll_disable_coherency)
- .align 2
- 3:
- .long coherency_phys_base - .
|