162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef __ASM_ARM_DIV64
362306a36Sopenharmony_ci#define __ASM_ARM_DIV64
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/types.h>
662306a36Sopenharmony_ci#include <asm/compiler.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * The semantics of __div64_32() are:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * uint32_t __div64_32(uint64_t *n, uint32_t base)
1262306a36Sopenharmony_ci * {
1362306a36Sopenharmony_ci * 	uint32_t remainder = *n % base;
1462306a36Sopenharmony_ci * 	*n = *n / base;
1562306a36Sopenharmony_ci * 	return remainder;
1662306a36Sopenharmony_ci * }
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * In other words, a 64-bit dividend with a 32-bit divisor producing
1962306a36Sopenharmony_ci * a 64-bit result and a 32-bit remainder.  To accomplish this optimally
2062306a36Sopenharmony_ci * we override the generic version in lib/div64.c to call our __do_div64
2162306a36Sopenharmony_ci * assembly implementation with completely non standard calling convention
2262306a36Sopenharmony_ci * for arguments and results (beware).
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_cistatic inline uint32_t __div64_32(uint64_t *n, uint32_t base)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	register unsigned int __base      asm("r4") = base;
2762306a36Sopenharmony_ci	register unsigned long long __n   asm("r0") = *n;
2862306a36Sopenharmony_ci	register unsigned long long __res asm("r2");
2962306a36Sopenharmony_ci	unsigned int __rem;
3062306a36Sopenharmony_ci	asm(	__asmeq("%0", "r0")
3162306a36Sopenharmony_ci		__asmeq("%1", "r2")
3262306a36Sopenharmony_ci		__asmeq("%2", "r4")
3362306a36Sopenharmony_ci		"bl	__do_div64"
3462306a36Sopenharmony_ci		: "+r" (__n), "=r" (__res)
3562306a36Sopenharmony_ci		: "r" (__base)
3662306a36Sopenharmony_ci		: "ip", "lr", "cc");
3762306a36Sopenharmony_ci	__rem = __n >> 32;
3862306a36Sopenharmony_ci	*n = __res;
3962306a36Sopenharmony_ci	return __rem;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci#define __div64_32 __div64_32
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#if !defined(CONFIG_AEABI)
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/*
4662306a36Sopenharmony_ci * In OABI configurations, some uses of the do_div function
4762306a36Sopenharmony_ci * cause gcc to run out of registers. To work around that,
4862306a36Sopenharmony_ci * we can force the use of the out-of-line version for
4962306a36Sopenharmony_ci * configurations that build a OABI kernel.
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_ci#define do_div(n, base) __div64_32(&(n), base)
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#else
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic inline uint64_t __arch_xprod_64(uint64_t m, uint64_t n, bool bias)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	unsigned long long res;
5862306a36Sopenharmony_ci	register unsigned int tmp asm("ip") = 0;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	if (!bias) {
6162306a36Sopenharmony_ci		asm (	"umull	%Q0, %R0, %Q1, %Q2\n\t"
6262306a36Sopenharmony_ci			"mov	%Q0, #0"
6362306a36Sopenharmony_ci			: "=&r" (res)
6462306a36Sopenharmony_ci			: "r" (m), "r" (n)
6562306a36Sopenharmony_ci			: "cc");
6662306a36Sopenharmony_ci	} else if (!(m & ((1ULL << 63) | (1ULL << 31)))) {
6762306a36Sopenharmony_ci		res = m;
6862306a36Sopenharmony_ci		asm (	"umlal	%Q0, %R0, %Q1, %Q2\n\t"
6962306a36Sopenharmony_ci			"mov	%Q0, #0"
7062306a36Sopenharmony_ci			: "+&r" (res)
7162306a36Sopenharmony_ci			: "r" (m), "r" (n)
7262306a36Sopenharmony_ci			: "cc");
7362306a36Sopenharmony_ci	} else {
7462306a36Sopenharmony_ci		asm (	"umull	%Q0, %R0, %Q2, %Q3\n\t"
7562306a36Sopenharmony_ci			"cmn	%Q0, %Q2\n\t"
7662306a36Sopenharmony_ci			"adcs	%R0, %R0, %R2\n\t"
7762306a36Sopenharmony_ci			"adc	%Q0, %1, #0"
7862306a36Sopenharmony_ci			: "=&r" (res), "+&r" (tmp)
7962306a36Sopenharmony_ci			: "r" (m), "r" (n)
8062306a36Sopenharmony_ci			: "cc");
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	if (!(m & ((1ULL << 63) | (1ULL << 31)))) {
8462306a36Sopenharmony_ci		asm (	"umlal	%R0, %Q0, %R1, %Q2\n\t"
8562306a36Sopenharmony_ci			"umlal	%R0, %Q0, %Q1, %R2\n\t"
8662306a36Sopenharmony_ci			"mov	%R0, #0\n\t"
8762306a36Sopenharmony_ci			"umlal	%Q0, %R0, %R1, %R2"
8862306a36Sopenharmony_ci			: "+&r" (res)
8962306a36Sopenharmony_ci			: "r" (m), "r" (n)
9062306a36Sopenharmony_ci			: "cc");
9162306a36Sopenharmony_ci	} else {
9262306a36Sopenharmony_ci		asm (	"umlal	%R0, %Q0, %R2, %Q3\n\t"
9362306a36Sopenharmony_ci			"umlal	%R0, %1, %Q2, %R3\n\t"
9462306a36Sopenharmony_ci			"mov	%R0, #0\n\t"
9562306a36Sopenharmony_ci			"adds	%Q0, %1, %Q0\n\t"
9662306a36Sopenharmony_ci			"adc	%R0, %R0, #0\n\t"
9762306a36Sopenharmony_ci			"umlal	%Q0, %R0, %R2, %R3"
9862306a36Sopenharmony_ci			: "+&r" (res), "+&r" (tmp)
9962306a36Sopenharmony_ci			: "r" (m), "r" (n)
10062306a36Sopenharmony_ci			: "cc");
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	return res;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci#define __arch_xprod_64 __arch_xprod_64
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#include <asm-generic/div64.h>
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#endif
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#endif
112