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