18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Coherency fabric: low level functions 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2012 Marvell 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Gregory CLEMENT <gregory.clement@free-electrons.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public 98c2ecf20Sopenharmony_ci * License version 2. This program is licensed "as is" without any 108c2ecf20Sopenharmony_ci * warranty of any kind, whether express or implied. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * This file implements the assembly function to add a CPU to the 138c2ecf20Sopenharmony_ci * coherency fabric. This function is called by each of the secondary 148c2ecf20Sopenharmony_ci * CPUs during their early boot in an SMP kernel, this why this 158c2ecf20Sopenharmony_ci * function have to callable from assembly. It can also be called by a 168c2ecf20Sopenharmony_ci * primary CPU from C code during its boot. 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/linkage.h> 208c2ecf20Sopenharmony_ci#define ARMADA_XP_CFB_CTL_REG_OFFSET 0x0 218c2ecf20Sopenharmony_ci#define ARMADA_XP_CFB_CFG_REG_OFFSET 0x4 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <asm/assembler.h> 248c2ecf20Sopenharmony_ci#include <asm/cp15.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci .text 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * Returns the coherency base address in r1 (r0 is untouched), or 0 if 298c2ecf20Sopenharmony_ci * the coherency fabric is not enabled. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ciENTRY(ll_get_coherency_base) 328c2ecf20Sopenharmony_ci mrc p15, 0, r1, c1, c0, 0 338c2ecf20Sopenharmony_ci tst r1, #CR_M @ Check MMU bit enabled 348c2ecf20Sopenharmony_ci bne 1f 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci /* 378c2ecf20Sopenharmony_ci * MMU is disabled, use the physical address of the coherency 388c2ecf20Sopenharmony_ci * base address, (or 0x0 if the coherency fabric is not mapped) 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci ldr_l r1, coherency_phys_base 418c2ecf20Sopenharmony_ci b 2f 428c2ecf20Sopenharmony_ci1: 438c2ecf20Sopenharmony_ci /* 448c2ecf20Sopenharmony_ci * MMU is enabled, use the virtual address of the coherency 458c2ecf20Sopenharmony_ci * base address. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci ldr r1, =coherency_base 488c2ecf20Sopenharmony_ci ldr r1, [r1] 498c2ecf20Sopenharmony_ci2: 508c2ecf20Sopenharmony_ci ret lr 518c2ecf20Sopenharmony_ciENDPROC(ll_get_coherency_base) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * Returns the coherency CPU mask in r3 (r0 is untouched). This 558c2ecf20Sopenharmony_ci * coherency CPU mask can be used with the coherency fabric 568c2ecf20Sopenharmony_ci * configuration and control registers. Note that the mask is already 578c2ecf20Sopenharmony_ci * endian-swapped as appropriate so that the calling functions do not 588c2ecf20Sopenharmony_ci * have to care about endianness issues while accessing the coherency 598c2ecf20Sopenharmony_ci * fabric registers 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ciENTRY(ll_get_coherency_cpumask) 628c2ecf20Sopenharmony_ci mrc p15, 0, r3, cr0, cr0, 5 638c2ecf20Sopenharmony_ci and r3, r3, #15 648c2ecf20Sopenharmony_ci mov r2, #(1 << 24) 658c2ecf20Sopenharmony_ci lsl r3, r2, r3 668c2ecf20Sopenharmony_ciARM_BE8(rev r3, r3) 678c2ecf20Sopenharmony_ci ret lr 688c2ecf20Sopenharmony_ciENDPROC(ll_get_coherency_cpumask) 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* 718c2ecf20Sopenharmony_ci * ll_add_cpu_to_smp_group(), ll_enable_coherency() and 728c2ecf20Sopenharmony_ci * ll_disable_coherency() use the strex/ldrex instructions while the 738c2ecf20Sopenharmony_ci * MMU can be disabled. The Armada XP SoC has an exclusive monitor 748c2ecf20Sopenharmony_ci * that tracks transactions to Device and/or SO memory and thanks to 758c2ecf20Sopenharmony_ci * that, exclusive transactions are functional even when the MMU is 768c2ecf20Sopenharmony_ci * disabled. 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciENTRY(ll_add_cpu_to_smp_group) 808c2ecf20Sopenharmony_ci /* 818c2ecf20Sopenharmony_ci * As r0 is not modified by ll_get_coherency_base() and 828c2ecf20Sopenharmony_ci * ll_get_coherency_cpumask(), we use it to temporarly save lr 838c2ecf20Sopenharmony_ci * and avoid it being modified by the branch and link 848c2ecf20Sopenharmony_ci * calls. This function is used very early in the secondary 858c2ecf20Sopenharmony_ci * CPU boot, and no stack is available at this point. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ci mov r0, lr 888c2ecf20Sopenharmony_ci bl ll_get_coherency_base 898c2ecf20Sopenharmony_ci /* Bail out if the coherency is not enabled */ 908c2ecf20Sopenharmony_ci cmp r1, #0 918c2ecf20Sopenharmony_ci reteq r0 928c2ecf20Sopenharmony_ci bl ll_get_coherency_cpumask 938c2ecf20Sopenharmony_ci mov lr, r0 948c2ecf20Sopenharmony_ci add r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET 958c2ecf20Sopenharmony_ci1: 968c2ecf20Sopenharmony_ci ldrex r2, [r0] 978c2ecf20Sopenharmony_ci orr r2, r2, r3 988c2ecf20Sopenharmony_ci strex r1, r2, [r0] 998c2ecf20Sopenharmony_ci cmp r1, #0 1008c2ecf20Sopenharmony_ci bne 1b 1018c2ecf20Sopenharmony_ci ret lr 1028c2ecf20Sopenharmony_ciENDPROC(ll_add_cpu_to_smp_group) 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ciENTRY(ll_enable_coherency) 1058c2ecf20Sopenharmony_ci /* 1068c2ecf20Sopenharmony_ci * As r0 is not modified by ll_get_coherency_base() and 1078c2ecf20Sopenharmony_ci * ll_get_coherency_cpumask(), we use it to temporarly save lr 1088c2ecf20Sopenharmony_ci * and avoid it being modified by the branch and link 1098c2ecf20Sopenharmony_ci * calls. This function is used very early in the secondary 1108c2ecf20Sopenharmony_ci * CPU boot, and no stack is available at this point. 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci mov r0, lr 1138c2ecf20Sopenharmony_ci bl ll_get_coherency_base 1148c2ecf20Sopenharmony_ci /* Bail out if the coherency is not enabled */ 1158c2ecf20Sopenharmony_ci cmp r1, #0 1168c2ecf20Sopenharmony_ci reteq r0 1178c2ecf20Sopenharmony_ci bl ll_get_coherency_cpumask 1188c2ecf20Sopenharmony_ci mov lr, r0 1198c2ecf20Sopenharmony_ci add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET 1208c2ecf20Sopenharmony_ci1: 1218c2ecf20Sopenharmony_ci ldrex r2, [r0] 1228c2ecf20Sopenharmony_ci orr r2, r2, r3 1238c2ecf20Sopenharmony_ci strex r1, r2, [r0] 1248c2ecf20Sopenharmony_ci cmp r1, #0 1258c2ecf20Sopenharmony_ci bne 1b 1268c2ecf20Sopenharmony_ci dsb 1278c2ecf20Sopenharmony_ci mov r0, #0 1288c2ecf20Sopenharmony_ci ret lr 1298c2ecf20Sopenharmony_ciENDPROC(ll_enable_coherency) 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ciENTRY(ll_disable_coherency) 1328c2ecf20Sopenharmony_ci /* 1338c2ecf20Sopenharmony_ci * As r0 is not modified by ll_get_coherency_base() and 1348c2ecf20Sopenharmony_ci * ll_get_coherency_cpumask(), we use it to temporarly save lr 1358c2ecf20Sopenharmony_ci * and avoid it being modified by the branch and link 1368c2ecf20Sopenharmony_ci * calls. This function is used very early in the secondary 1378c2ecf20Sopenharmony_ci * CPU boot, and no stack is available at this point. 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci mov r0, lr 1408c2ecf20Sopenharmony_ci bl ll_get_coherency_base 1418c2ecf20Sopenharmony_ci /* Bail out if the coherency is not enabled */ 1428c2ecf20Sopenharmony_ci cmp r1, #0 1438c2ecf20Sopenharmony_ci reteq r0 1448c2ecf20Sopenharmony_ci bl ll_get_coherency_cpumask 1458c2ecf20Sopenharmony_ci mov lr, r0 1468c2ecf20Sopenharmony_ci add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET 1478c2ecf20Sopenharmony_ci1: 1488c2ecf20Sopenharmony_ci ldrex r2, [r0] 1498c2ecf20Sopenharmony_ci bic r2, r2, r3 1508c2ecf20Sopenharmony_ci strex r1, r2, [r0] 1518c2ecf20Sopenharmony_ci cmp r1, #0 1528c2ecf20Sopenharmony_ci bne 1b 1538c2ecf20Sopenharmony_ci dsb 1548c2ecf20Sopenharmony_ci ret lr 1558c2ecf20Sopenharmony_ciENDPROC(ll_disable_coherency) 156