/* * Coherency fabric: low level functions * * Copyright (C) 2012 Marvell * * Gregory CLEMENT * * 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 #define ARMADA_XP_CFB_CTL_REG_OFFSET 0x0 #define ARMADA_XP_CFB_CFG_REG_OFFSET 0x4 #include #include .text /* Returns with the coherency address in r1 (r0 is untouched)*/ ENTRY(ll_get_coherency_base) mrc p15, 0, r1, c1, c0, 0 tst r1, #CR_M @ Check MMU bit enabled bne 1f /* use physical address of the coherency register */ adr r1, 3f ldr r3, [r1] ldr r1, [r1, r3] b 2f 1: /* use virtual address of the coherency register */ ldr r1, =coherency_base ldr r1, [r1] 2: mov pc, lr ENDPROC(ll_get_coherency_base) /* Returns with the CPU ID in r3 (r0 is untouched)*/ ENTRY(ll_get_cpuid) mrc 15, 0, r3, cr0, cr0, 5 and r3, r3, #15 mov r2, #(1 << 24) lsl r3, r2, r3 ARM_BE8(rev r1, r1) mov pc, lr ENDPROC(ll_get_cpuid) /* ll_add_cpu_to_smp_group, ll_enable_coherency and * ll_disable_coherency use strex/ldrex whereas MMU can be off. The * Armada XP SoC has an exclusive monitor that can track transactions * to Device and/or SO and as such also when MMU is disabled the * exclusive transactions will be functional */ ENTRY(ll_add_cpu_to_smp_group) /* * r0 being untouched in ll_get_coherency_base and * ll_get_cpuid, we can use it to save lr modifing it with the * following bl */ mov r0, lr bl ll_get_coherency_base bl ll_get_cpuid 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 mov pc, lr ENDPROC(ll_add_cpu_to_smp_group) ENTRY(ll_enable_coherency) /* * r0 being untouched in ll_get_coherency_base and * ll_get_cpuid, we can use it to save lr modifing it with the * following bl */ mov r0, lr bl ll_get_coherency_base bl ll_get_cpuid 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 mov pc, lr ENDPROC(ll_enable_coherency) ENTRY(ll_disable_coherency) /* * r0 being untouched in ll_get_coherency_base and * ll_get_cpuid, we can use it to save lr modifing it with the * following bl */ mov r0, lr bl ll_get_coherency_base bl ll_get_cpuid 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 mov pc, lr ENDPROC(ll_disable_coherency) .align 2 3: .long coherency_phys_base - .