1*4882a593Smuzhiyun/* 2*4882a593Smuzhiyun * Coherency fabric: low level functions 3*4882a593Smuzhiyun * 4*4882a593Smuzhiyun * Copyright (C) 2012 Marvell 5*4882a593Smuzhiyun * 6*4882a593Smuzhiyun * Gregory CLEMENT <gregory.clement@free-electrons.com> 7*4882a593Smuzhiyun * 8*4882a593Smuzhiyun * This file is licensed under the terms of the GNU General Public 9*4882a593Smuzhiyun * License version 2. This program is licensed "as is" without any 10*4882a593Smuzhiyun * warranty of any kind, whether express or implied. 11*4882a593Smuzhiyun * 12*4882a593Smuzhiyun * This file implements the assembly function to add a CPU to the 13*4882a593Smuzhiyun * coherency fabric. This function is called by each of the secondary 14*4882a593Smuzhiyun * CPUs during their early boot in an SMP kernel, this why this 15*4882a593Smuzhiyun * function have to callable from assembly. It can also be called by a 16*4882a593Smuzhiyun * primary CPU from C code during its boot. 17*4882a593Smuzhiyun */ 18*4882a593Smuzhiyun 19*4882a593Smuzhiyun#include <linux/linkage.h> 20*4882a593Smuzhiyun#define ARMADA_XP_CFB_CTL_REG_OFFSET 0x0 21*4882a593Smuzhiyun#define ARMADA_XP_CFB_CFG_REG_OFFSET 0x4 22*4882a593Smuzhiyun 23*4882a593Smuzhiyun#include <asm/assembler.h> 24*4882a593Smuzhiyun#include <asm/cp15.h> 25*4882a593Smuzhiyun 26*4882a593Smuzhiyun .text 27*4882a593Smuzhiyun/* 28*4882a593Smuzhiyun * Returns the coherency base address in r1 (r0 is untouched), or 0 if 29*4882a593Smuzhiyun * the coherency fabric is not enabled. 30*4882a593Smuzhiyun */ 31*4882a593SmuzhiyunENTRY(ll_get_coherency_base) 32*4882a593Smuzhiyun mrc p15, 0, r1, c1, c0, 0 33*4882a593Smuzhiyun tst r1, #CR_M @ Check MMU bit enabled 34*4882a593Smuzhiyun bne 1f 35*4882a593Smuzhiyun 36*4882a593Smuzhiyun /* 37*4882a593Smuzhiyun * MMU is disabled, use the physical address of the coherency 38*4882a593Smuzhiyun * base address, (or 0x0 if the coherency fabric is not mapped) 39*4882a593Smuzhiyun */ 40*4882a593Smuzhiyun adr r1, 3f 41*4882a593Smuzhiyun ldr r3, [r1] 42*4882a593Smuzhiyun ldr r1, [r1, r3] 43*4882a593Smuzhiyun b 2f 44*4882a593Smuzhiyun1: 45*4882a593Smuzhiyun /* 46*4882a593Smuzhiyun * MMU is enabled, use the virtual address of the coherency 47*4882a593Smuzhiyun * base address. 48*4882a593Smuzhiyun */ 49*4882a593Smuzhiyun ldr r1, =coherency_base 50*4882a593Smuzhiyun ldr r1, [r1] 51*4882a593Smuzhiyun2: 52*4882a593Smuzhiyun ret lr 53*4882a593SmuzhiyunENDPROC(ll_get_coherency_base) 54*4882a593Smuzhiyun 55*4882a593Smuzhiyun/* 56*4882a593Smuzhiyun * Returns the coherency CPU mask in r3 (r0 is untouched). This 57*4882a593Smuzhiyun * coherency CPU mask can be used with the coherency fabric 58*4882a593Smuzhiyun * configuration and control registers. Note that the mask is already 59*4882a593Smuzhiyun * endian-swapped as appropriate so that the calling functions do not 60*4882a593Smuzhiyun * have to care about endianness issues while accessing the coherency 61*4882a593Smuzhiyun * fabric registers 62*4882a593Smuzhiyun */ 63*4882a593SmuzhiyunENTRY(ll_get_coherency_cpumask) 64*4882a593Smuzhiyun mrc p15, 0, r3, cr0, cr0, 5 65*4882a593Smuzhiyun and r3, r3, #15 66*4882a593Smuzhiyun mov r2, #(1 << 24) 67*4882a593Smuzhiyun lsl r3, r2, r3 68*4882a593SmuzhiyunARM_BE8(rev r3, r3) 69*4882a593Smuzhiyun ret lr 70*4882a593SmuzhiyunENDPROC(ll_get_coherency_cpumask) 71*4882a593Smuzhiyun 72*4882a593Smuzhiyun/* 73*4882a593Smuzhiyun * ll_add_cpu_to_smp_group(), ll_enable_coherency() and 74*4882a593Smuzhiyun * ll_disable_coherency() use the strex/ldrex instructions while the 75*4882a593Smuzhiyun * MMU can be disabled. The Armada XP SoC has an exclusive monitor 76*4882a593Smuzhiyun * that tracks transactions to Device and/or SO memory and thanks to 77*4882a593Smuzhiyun * that, exclusive transactions are functional even when the MMU is 78*4882a593Smuzhiyun * disabled. 79*4882a593Smuzhiyun */ 80*4882a593Smuzhiyun 81*4882a593SmuzhiyunENTRY(ll_add_cpu_to_smp_group) 82*4882a593Smuzhiyun /* 83*4882a593Smuzhiyun * As r0 is not modified by ll_get_coherency_base() and 84*4882a593Smuzhiyun * ll_get_coherency_cpumask(), we use it to temporarly save lr 85*4882a593Smuzhiyun * and avoid it being modified by the branch and link 86*4882a593Smuzhiyun * calls. This function is used very early in the secondary 87*4882a593Smuzhiyun * CPU boot, and no stack is available at this point. 88*4882a593Smuzhiyun */ 89*4882a593Smuzhiyun mov r0, lr 90*4882a593Smuzhiyun bl ll_get_coherency_base 91*4882a593Smuzhiyun /* Bail out if the coherency is not enabled */ 92*4882a593Smuzhiyun cmp r1, #0 93*4882a593Smuzhiyun reteq r0 94*4882a593Smuzhiyun bl ll_get_coherency_cpumask 95*4882a593Smuzhiyun mov lr, r0 96*4882a593Smuzhiyun add r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET 97*4882a593Smuzhiyun1: 98*4882a593Smuzhiyun ldrex r2, [r0] 99*4882a593Smuzhiyun orr r2, r2, r3 100*4882a593Smuzhiyun strex r1, r2, [r0] 101*4882a593Smuzhiyun cmp r1, #0 102*4882a593Smuzhiyun bne 1b 103*4882a593Smuzhiyun ret lr 104*4882a593SmuzhiyunENDPROC(ll_add_cpu_to_smp_group) 105*4882a593Smuzhiyun 106*4882a593SmuzhiyunENTRY(ll_enable_coherency) 107*4882a593Smuzhiyun /* 108*4882a593Smuzhiyun * As r0 is not modified by ll_get_coherency_base() and 109*4882a593Smuzhiyun * ll_get_coherency_cpumask(), we use it to temporarly save lr 110*4882a593Smuzhiyun * and avoid it being modified by the branch and link 111*4882a593Smuzhiyun * calls. This function is used very early in the secondary 112*4882a593Smuzhiyun * CPU boot, and no stack is available at this point. 113*4882a593Smuzhiyun */ 114*4882a593Smuzhiyun mov r0, lr 115*4882a593Smuzhiyun bl ll_get_coherency_base 116*4882a593Smuzhiyun /* Bail out if the coherency is not enabled */ 117*4882a593Smuzhiyun cmp r1, #0 118*4882a593Smuzhiyun reteq r0 119*4882a593Smuzhiyun bl ll_get_coherency_cpumask 120*4882a593Smuzhiyun mov lr, r0 121*4882a593Smuzhiyun add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET 122*4882a593Smuzhiyun1: 123*4882a593Smuzhiyun ldrex r2, [r0] 124*4882a593Smuzhiyun orr r2, r2, r3 125*4882a593Smuzhiyun strex r1, r2, [r0] 126*4882a593Smuzhiyun cmp r1, #0 127*4882a593Smuzhiyun bne 1b 128*4882a593Smuzhiyun dsb 129*4882a593Smuzhiyun mov r0, #0 130*4882a593Smuzhiyun ret lr 131*4882a593SmuzhiyunENDPROC(ll_enable_coherency) 132*4882a593Smuzhiyun 133*4882a593SmuzhiyunENTRY(ll_disable_coherency) 134*4882a593Smuzhiyun /* 135*4882a593Smuzhiyun * As r0 is not modified by ll_get_coherency_base() and 136*4882a593Smuzhiyun * ll_get_coherency_cpumask(), we use it to temporarly save lr 137*4882a593Smuzhiyun * and avoid it being modified by the branch and link 138*4882a593Smuzhiyun * calls. This function is used very early in the secondary 139*4882a593Smuzhiyun * CPU boot, and no stack is available at this point. 140*4882a593Smuzhiyun */ 141*4882a593Smuzhiyun mov r0, lr 142*4882a593Smuzhiyun bl ll_get_coherency_base 143*4882a593Smuzhiyun /* Bail out if the coherency is not enabled */ 144*4882a593Smuzhiyun cmp r1, #0 145*4882a593Smuzhiyun reteq r0 146*4882a593Smuzhiyun bl ll_get_coherency_cpumask 147*4882a593Smuzhiyun mov lr, r0 148*4882a593Smuzhiyun add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET 149*4882a593Smuzhiyun1: 150*4882a593Smuzhiyun ldrex r2, [r0] 151*4882a593Smuzhiyun bic r2, r2, r3 152*4882a593Smuzhiyun strex r1, r2, [r0] 153*4882a593Smuzhiyun cmp r1, #0 154*4882a593Smuzhiyun bne 1b 155*4882a593Smuzhiyun dsb 156*4882a593Smuzhiyun ret lr 157*4882a593SmuzhiyunENDPROC(ll_disable_coherency) 158*4882a593Smuzhiyun 159*4882a593Smuzhiyun .align 2 160*4882a593Smuzhiyun3: 161*4882a593Smuzhiyun .long coherency_phys_base - . 162