18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2015 Imagination Technologies
48c2ecf20Sopenharmony_ci * Author: Alex Smith <alex.smith@imgtec.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <asm/sgidefs.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <asm/asm.h>
128c2ecf20Sopenharmony_ci#include <asm/page.h>
138c2ecf20Sopenharmony_ci#include <asm/vdso.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistatic inline unsigned long get_vdso_base(void)
168c2ecf20Sopenharmony_ci{
178c2ecf20Sopenharmony_ci	unsigned long addr;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	/*
208c2ecf20Sopenharmony_ci	 * We can't use cpu_has_mips_r6 since it needs the cpu_data[]
218c2ecf20Sopenharmony_ci	 * kernel symbol.
228c2ecf20Sopenharmony_ci	 */
238c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_MIPSR6
248c2ecf20Sopenharmony_ci	/*
258c2ecf20Sopenharmony_ci	 * lapc <symbol> is an alias to addiupc reg, <symbol> - .
268c2ecf20Sopenharmony_ci	 *
278c2ecf20Sopenharmony_ci	 * We can't use addiupc because there is no label-label
288c2ecf20Sopenharmony_ci	 * support for the addiupc reloc
298c2ecf20Sopenharmony_ci	 */
308c2ecf20Sopenharmony_ci	__asm__("lapc	%0, _start			\n"
318c2ecf20Sopenharmony_ci		: "=r" (addr) : :);
328c2ecf20Sopenharmony_ci#else
338c2ecf20Sopenharmony_ci	/*
348c2ecf20Sopenharmony_ci	 * Get the base load address of the VDSO. We have to avoid generating
358c2ecf20Sopenharmony_ci	 * relocations and references to the GOT because ld.so does not peform
368c2ecf20Sopenharmony_ci	 * relocations on the VDSO. We use the current offset from the VDSO base
378c2ecf20Sopenharmony_ci	 * and perform a PC-relative branch which gives the absolute address in
388c2ecf20Sopenharmony_ci	 * ra, and take the difference. The assembler chokes on
398c2ecf20Sopenharmony_ci	 * "li %0, _start - .", so embed the offset as a word and branch over
408c2ecf20Sopenharmony_ci	 * it.
418c2ecf20Sopenharmony_ci	 *
428c2ecf20Sopenharmony_ci	 */
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	__asm__(
458c2ecf20Sopenharmony_ci	"	.set push				\n"
468c2ecf20Sopenharmony_ci	"	.set noreorder				\n"
478c2ecf20Sopenharmony_ci	"	bal	1f				\n"
488c2ecf20Sopenharmony_ci	"	 nop					\n"
498c2ecf20Sopenharmony_ci	"	.word	_start - .			\n"
508c2ecf20Sopenharmony_ci	"1:	lw	%0, 0($31)			\n"
518c2ecf20Sopenharmony_ci	"	" STR(PTR_ADDU) " %0, $31, %0		\n"
528c2ecf20Sopenharmony_ci	"	.set pop				\n"
538c2ecf20Sopenharmony_ci	: "=r" (addr)
548c2ecf20Sopenharmony_ci	:
558c2ecf20Sopenharmony_ci	: "$31");
568c2ecf20Sopenharmony_ci#endif /* CONFIG_CPU_MIPSR6 */
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	return addr;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic inline const struct vdso_data *get_vdso_data(void)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	return (const struct vdso_data *)(get_vdso_base() - PAGE_SIZE);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#ifdef CONFIG_CLKSRC_MIPS_GIC
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic inline void __iomem *get_gic(const struct vdso_data *data)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	return (void __iomem *)((unsigned long)data & PAGE_MASK) - PAGE_SIZE;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#endif /* CONFIG_CLKSRC_MIPS_GIC */
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#endif /* __ASSEMBLY__ */
76