xref: /rk3399_rockchip-uboot/lib/div64.c (revision 78acc472d9719316f22e002a009a998d9ceec29d)
1*78acc472SPeter Tyser /*
2*78acc472SPeter Tyser  * Copyright (C) 2003 Bernardo Innocenti <bernie@develer.com>
3*78acc472SPeter Tyser  *
4*78acc472SPeter Tyser  * Based on former do_div() implementation from asm-parisc/div64.h:
5*78acc472SPeter Tyser  *	Copyright (C) 1999 Hewlett-Packard Co
6*78acc472SPeter Tyser  *	Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
7*78acc472SPeter Tyser  *
8*78acc472SPeter Tyser  *
9*78acc472SPeter Tyser  * Generic C version of 64bit/32bit division and modulo, with
10*78acc472SPeter Tyser  * 64bit result and 32bit remainder.
11*78acc472SPeter Tyser  *
12*78acc472SPeter Tyser  * The fast case for (n>>32 == 0) is handled inline by do_div().
13*78acc472SPeter Tyser  *
14*78acc472SPeter Tyser  * Code generated for this function might be very inefficient
15*78acc472SPeter Tyser  * for some CPUs. __div64_32() can be overridden by linking arch-specific
16*78acc472SPeter Tyser  * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S.
17*78acc472SPeter Tyser  */
18*78acc472SPeter Tyser 
19*78acc472SPeter Tyser #include <linux/types.h>
20*78acc472SPeter Tyser 
21*78acc472SPeter Tyser uint32_t __div64_32(uint64_t *n, uint32_t base)
22*78acc472SPeter Tyser {
23*78acc472SPeter Tyser 	uint64_t rem = *n;
24*78acc472SPeter Tyser 	uint64_t b = base;
25*78acc472SPeter Tyser 	uint64_t res, d = 1;
26*78acc472SPeter Tyser 	uint32_t high = rem >> 32;
27*78acc472SPeter Tyser 
28*78acc472SPeter Tyser 	/* Reduce the thing a bit first */
29*78acc472SPeter Tyser 	res = 0;
30*78acc472SPeter Tyser 	if (high >= base) {
31*78acc472SPeter Tyser 		high /= base;
32*78acc472SPeter Tyser 		res = (uint64_t) high << 32;
33*78acc472SPeter Tyser 		rem -= (uint64_t) (high*base) << 32;
34*78acc472SPeter Tyser 	}
35*78acc472SPeter Tyser 
36*78acc472SPeter Tyser 	while ((int64_t)b > 0 && b < rem) {
37*78acc472SPeter Tyser 		b = b+b;
38*78acc472SPeter Tyser 		d = d+d;
39*78acc472SPeter Tyser 	}
40*78acc472SPeter Tyser 
41*78acc472SPeter Tyser 	do {
42*78acc472SPeter Tyser 		if (rem >= b) {
43*78acc472SPeter Tyser 			rem -= b;
44*78acc472SPeter Tyser 			res += d;
45*78acc472SPeter Tyser 		}
46*78acc472SPeter Tyser 		b >>= 1;
47*78acc472SPeter Tyser 		d >>= 1;
48*78acc472SPeter Tyser 	} while (d);
49*78acc472SPeter Tyser 
50*78acc472SPeter Tyser 	*n = res;
51*78acc472SPeter Tyser 	return rem;
52*78acc472SPeter Tyser }
53