xref: /linux/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.h (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1 /* SPDX-License-Identifier: MIT */
2 
3 /* Copyright 2024 Advanced Micro Devices, Inc. */
4 
5 #ifndef __SPL_FIXED31_32_H__
6 #define __SPL_FIXED31_32_H__
7 
8 #include "os_types.h"
9 #include "spl_os_types.h"   // swap
10 #ifndef ASSERT
11 #define ASSERT(_bool) ((void *)0)
12 #endif
13 
14 #ifndef LLONG_MAX
15 #define LLONG_MAX 9223372036854775807ll
16 #endif
17 #ifndef LLONG_MIN
18 #define LLONG_MIN (-LLONG_MAX - 1ll)
19 #endif
20 
21 #define FIXED31_32_BITS_PER_FRACTIONAL_PART 32
22 #ifndef LLONG_MIN
23 #define LLONG_MIN (1LL<<63)
24 #endif
25 #ifndef LLONG_MAX
26 #define LLONG_MAX (-1LL>>1)
27 #endif
28 
29 /*
30  * @brief
31  * Arithmetic operations on real numbers
32  * represented as fixed-point numbers.
33  * There are: 1 bit for sign,
34  * 31 bit for integer part,
35  * 32 bits for fractional part.
36  *
37  * @note
38  * Currently, overflows and underflows are asserted;
39  * no special result returned.
40  */
41 
42 struct spl_fixed31_32 {
43 	long long value;
44 };
45 
46 
47 /*
48  * @brief
49  * Useful constants
50  */
51 
52 static const struct spl_fixed31_32 spl_fixpt_zero = { 0 };
53 static const struct spl_fixed31_32 spl_fixpt_epsilon = { 1LL };
54 static const struct spl_fixed31_32 spl_fixpt_half = { 0x80000000LL };
55 static const struct spl_fixed31_32 spl_fixpt_one = { 0x100000000LL };
56 
57 /*
58  * @brief
59  * Initialization routines
60  */
61 
62 /*
63  * @brief
64  * result = numerator / denominator
65  */
66 struct spl_fixed31_32 spl_fixpt_from_fraction(long long numerator, long long denominator);
67 
68 /*
69  * @brief
70  * result = arg
71  */
spl_fixpt_from_int(int arg)72 static inline struct spl_fixed31_32 spl_fixpt_from_int(int arg)
73 {
74 	struct spl_fixed31_32 res;
75 
76 	res.value = (long long) arg << FIXED31_32_BITS_PER_FRACTIONAL_PART;
77 
78 	return res;
79 }
80 
81 /*
82  * @brief
83  * Unary operators
84  */
85 
86 /*
87  * @brief
88  * result = -arg
89  */
spl_fixpt_neg(struct spl_fixed31_32 arg)90 static inline struct spl_fixed31_32 spl_fixpt_neg(struct spl_fixed31_32 arg)
91 {
92 	struct spl_fixed31_32 res;
93 
94 	res.value = -arg.value;
95 
96 	return res;
97 }
98 
99 /*
100  * @brief
101  * result = abs(arg) := (arg >= 0) ? arg : -arg
102  */
spl_fixpt_abs(struct spl_fixed31_32 arg)103 static inline struct spl_fixed31_32 spl_fixpt_abs(struct spl_fixed31_32 arg)
104 {
105 	if (arg.value < 0)
106 		return spl_fixpt_neg(arg);
107 	else
108 		return arg;
109 }
110 
111 /*
112  * @brief
113  * Binary relational operators
114  */
115 
116 /*
117  * @brief
118  * result = arg1 < arg2
119  */
spl_fixpt_lt(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)120 static inline bool spl_fixpt_lt(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
121 {
122 	return arg1.value < arg2.value;
123 }
124 
125 /*
126  * @brief
127  * result = arg1 <= arg2
128  */
spl_fixpt_le(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)129 static inline bool spl_fixpt_le(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
130 {
131 	return arg1.value <= arg2.value;
132 }
133 
134 /*
135  * @brief
136  * result = arg1 == arg2
137  */
spl_fixpt_eq(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)138 static inline bool spl_fixpt_eq(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
139 {
140 	return arg1.value == arg2.value;
141 }
142 
143 /*
144  * @brief
145  * result = min(arg1, arg2) := (arg1 <= arg2) ? arg1 : arg2
146  */
spl_fixpt_min(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)147 static inline struct spl_fixed31_32 spl_fixpt_min(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
148 {
149 	if (arg1.value <= arg2.value)
150 		return arg1;
151 	else
152 		return arg2;
153 }
154 
155 /*
156  * @brief
157  * result = max(arg1, arg2) := (arg1 <= arg2) ? arg2 : arg1
158  */
spl_fixpt_max(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)159 static inline struct spl_fixed31_32 spl_fixpt_max(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
160 {
161 	if (arg1.value <= arg2.value)
162 		return arg2;
163 	else
164 		return arg1;
165 }
166 
167 /*
168  * @brief
169  *          | min_value, when arg <= min_value
170  * result = | arg, when min_value < arg < max_value
171  *          | max_value, when arg >= max_value
172  */
spl_fixpt_clamp(struct spl_fixed31_32 arg,struct spl_fixed31_32 min_value,struct spl_fixed31_32 max_value)173 static inline struct spl_fixed31_32 spl_fixpt_clamp(
174 	struct spl_fixed31_32 arg,
175 	struct spl_fixed31_32 min_value,
176 	struct spl_fixed31_32 max_value)
177 {
178 	if (spl_fixpt_le(arg, min_value))
179 		return min_value;
180 	else if (spl_fixpt_le(max_value, arg))
181 		return max_value;
182 	else
183 		return arg;
184 }
185 
186 /*
187  * @brief
188  * Binary shift operators
189  */
190 
191 /*
192  * @brief
193  * result = arg << shift
194  */
spl_fixpt_shl(struct spl_fixed31_32 arg,unsigned char shift)195 static inline struct spl_fixed31_32 spl_fixpt_shl(struct spl_fixed31_32 arg, unsigned char shift)
196 {
197 	ASSERT(((arg.value >= 0) && (arg.value <= LLONG_MAX >> shift)) ||
198 		((arg.value < 0) && (arg.value >= ~(LLONG_MAX >> shift))));
199 
200 	arg.value = arg.value << shift;
201 
202 	return arg;
203 }
204 
205 /*
206  * @brief
207  * result = arg >> shift
208  */
spl_fixpt_shr(struct spl_fixed31_32 arg,unsigned char shift)209 static inline struct spl_fixed31_32 spl_fixpt_shr(struct spl_fixed31_32 arg, unsigned char shift)
210 {
211 	bool negative = arg.value < 0;
212 
213 	if (negative)
214 		arg.value = -arg.value;
215 	arg.value = arg.value >> shift;
216 	if (negative)
217 		arg.value = -arg.value;
218 	return arg;
219 }
220 
221 /*
222  * @brief
223  * Binary additive operators
224  */
225 
226 /*
227  * @brief
228  * result = arg1 + arg2
229  */
spl_fixpt_add(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)230 static inline struct spl_fixed31_32 spl_fixpt_add(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
231 {
232 	struct spl_fixed31_32 res;
233 
234 	ASSERT(((arg1.value >= 0) && (LLONG_MAX - arg1.value >= arg2.value)) ||
235 		((arg1.value < 0) && (LLONG_MIN - arg1.value <= arg2.value)));
236 
237 	res.value = arg1.value + arg2.value;
238 
239 	return res;
240 }
241 
242 /*
243  * @brief
244  * result = arg1 + arg2
245  */
spl_fixpt_add_int(struct spl_fixed31_32 arg1,int arg2)246 static inline struct spl_fixed31_32 spl_fixpt_add_int(struct spl_fixed31_32 arg1, int arg2)
247 {
248 	return spl_fixpt_add(arg1, spl_fixpt_from_int(arg2));
249 }
250 
251 /*
252  * @brief
253  * result = arg1 - arg2
254  */
spl_fixpt_sub(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)255 static inline struct spl_fixed31_32 spl_fixpt_sub(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
256 {
257 	struct spl_fixed31_32 res;
258 
259 	ASSERT(((arg2.value >= 0) && (LLONG_MIN + arg2.value <= arg1.value)) ||
260 		((arg2.value < 0) && (LLONG_MAX + arg2.value >= arg1.value)));
261 
262 	res.value = arg1.value - arg2.value;
263 
264 	return res;
265 }
266 
267 /*
268  * @brief
269  * result = arg1 - arg2
270  */
spl_fixpt_sub_int(struct spl_fixed31_32 arg1,int arg2)271 static inline struct spl_fixed31_32 spl_fixpt_sub_int(struct spl_fixed31_32 arg1, int arg2)
272 {
273 	return spl_fixpt_sub(arg1, spl_fixpt_from_int(arg2));
274 }
275 
276 
277 /*
278  * @brief
279  * Binary multiplicative operators
280  */
281 
282 /*
283  * @brief
284  * result = arg1 * arg2
285  */
286 struct spl_fixed31_32 spl_fixpt_mul(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2);
287 
288 
289 /*
290  * @brief
291  * result = arg1 * arg2
292  */
spl_fixpt_mul_int(struct spl_fixed31_32 arg1,int arg2)293 static inline struct spl_fixed31_32 spl_fixpt_mul_int(struct spl_fixed31_32 arg1, int arg2)
294 {
295 	return spl_fixpt_mul(arg1, spl_fixpt_from_int(arg2));
296 }
297 
298 /*
299  * @brief
300  * result = square(arg) := arg * arg
301  */
302 struct spl_fixed31_32 spl_fixpt_sqr(struct spl_fixed31_32 arg);
303 
304 /*
305  * @brief
306  * result = arg1 / arg2
307  */
spl_fixpt_div_int(struct spl_fixed31_32 arg1,long long arg2)308 static inline struct spl_fixed31_32 spl_fixpt_div_int(struct spl_fixed31_32 arg1, long long arg2)
309 {
310 	return spl_fixpt_from_fraction(arg1.value, spl_fixpt_from_int((int)arg2).value);
311 }
312 
313 /*
314  * @brief
315  * result = arg1 / arg2
316  */
spl_fixpt_div(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)317 static inline struct spl_fixed31_32 spl_fixpt_div(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
318 {
319 	return spl_fixpt_from_fraction(arg1.value, arg2.value);
320 }
321 
322 /*
323  * @brief
324  * Reciprocal function
325  */
326 
327 /*
328  * @brief
329  * result = reciprocal(arg) := 1 / arg
330  *
331  * @note
332  * No special actions taken in case argument is zero.
333  */
334 struct spl_fixed31_32 spl_fixpt_recip(struct spl_fixed31_32 arg);
335 
336 /*
337  * @brief
338  * Trigonometric functions
339  */
340 
341 /*
342  * @brief
343  * result = sinc(arg) := sin(arg) / arg
344  *
345  * @note
346  * Argument specified in radians,
347  * internally it's normalized to [-2pi...2pi] range.
348  */
349 struct spl_fixed31_32 spl_fixpt_sinc(struct spl_fixed31_32 arg);
350 
351 /*
352  * @brief
353  * result = sin(arg)
354  *
355  * @note
356  * Argument specified in radians,
357  * internally it's normalized to [-2pi...2pi] range.
358  */
359 struct spl_fixed31_32 spl_fixpt_sin(struct spl_fixed31_32 arg);
360 
361 /*
362  * @brief
363  * result = cos(arg)
364  *
365  * @note
366  * Argument specified in radians
367  * and should be in [-2pi...2pi] range -
368  * passing arguments outside that range
369  * will cause incorrect result!
370  */
371 struct spl_fixed31_32 spl_fixpt_cos(struct spl_fixed31_32 arg);
372 
373 /*
374  * @brief
375  * Transcendent functions
376  */
377 
378 /*
379  * @brief
380  * result = exp(arg)
381  *
382  * @note
383  * Currently, function is verified for abs(arg) <= 1.
384  */
385 struct spl_fixed31_32 spl_fixpt_exp(struct spl_fixed31_32 arg);
386 
387 /*
388  * @brief
389  * result = log(arg)
390  *
391  * @note
392  * Currently, abs(arg) should be less than 1.
393  * No normalization is done.
394  * Currently, no special actions taken
395  * in case of invalid argument(s). Take care!
396  */
397 struct spl_fixed31_32 spl_fixpt_log(struct spl_fixed31_32 arg);
398 
399 /*
400  * @brief
401  * Power function
402  */
403 
404 /*
405  * @brief
406  * result = pow(arg1, arg2)
407  *
408  * @note
409  * Currently, abs(arg1) should be less than 1. Take care!
410  */
spl_fixpt_pow(struct spl_fixed31_32 arg1,struct spl_fixed31_32 arg2)411 static inline struct spl_fixed31_32 spl_fixpt_pow(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
412 {
413 	if (arg1.value == 0)
414 		return arg2.value == 0 ? spl_fixpt_one : spl_fixpt_zero;
415 
416 	return spl_fixpt_exp(
417 		spl_fixpt_mul(
418 			spl_fixpt_log(arg1),
419 			arg2));
420 }
421 
422 /*
423  * @brief
424  * Rounding functions
425  */
426 
427 /*
428  * @brief
429  * result = floor(arg) := greatest integer lower than or equal to arg
430  */
spl_fixpt_floor(struct spl_fixed31_32 arg)431 static inline int spl_fixpt_floor(struct spl_fixed31_32 arg)
432 {
433 	unsigned long long arg_value = arg.value > 0 ? arg.value : -arg.value;
434 
435 	if (arg.value >= 0)
436 		return (int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
437 	else
438 		return -(int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
439 }
440 
441 /*
442  * @brief
443  * result = round(arg) := integer nearest to arg
444  */
spl_fixpt_round(struct spl_fixed31_32 arg)445 static inline int spl_fixpt_round(struct spl_fixed31_32 arg)
446 {
447 	unsigned long long arg_value = arg.value > 0 ? arg.value : -arg.value;
448 
449 	const long long summand = spl_fixpt_half.value;
450 
451 	ASSERT(LLONG_MAX - (long long)arg_value >= summand);
452 
453 	arg_value += summand;
454 
455 	if (arg.value >= 0)
456 		return (int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
457 	else
458 		return -(int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
459 }
460 
461 /*
462  * @brief
463  * result = ceil(arg) := lowest integer greater than or equal to arg
464  */
spl_fixpt_ceil(struct spl_fixed31_32 arg)465 static inline int spl_fixpt_ceil(struct spl_fixed31_32 arg)
466 {
467 	unsigned long long arg_value = arg.value > 0 ? arg.value : -arg.value;
468 
469 	const long long summand = spl_fixpt_one.value -
470 		spl_fixpt_epsilon.value;
471 
472 	ASSERT(LLONG_MAX - (long long)arg_value >= summand);
473 
474 	arg_value += summand;
475 
476 	if (arg.value >= 0)
477 		return (int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
478 	else
479 		return -(int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
480 }
481 
482 /* the following two function are used in scaler hw programming to convert fixed
483  * point value to format 2 bits from integer part and 19 bits from fractional
484  * part. The same applies for u0d19, 0 bits from integer part and 19 bits from
485  * fractional
486  */
487 
488 unsigned int spl_fixpt_u4d19(struct spl_fixed31_32 arg);
489 
490 unsigned int spl_fixpt_u3d19(struct spl_fixed31_32 arg);
491 
492 unsigned int spl_fixpt_u2d19(struct spl_fixed31_32 arg);
493 
494 unsigned int spl_fixpt_u0d19(struct spl_fixed31_32 arg);
495 
496 unsigned int spl_fixpt_clamp_u0d14(struct spl_fixed31_32 arg);
497 
498 unsigned int spl_fixpt_clamp_u0d10(struct spl_fixed31_32 arg);
499 
500 int spl_fixpt_s4d19(struct spl_fixed31_32 arg);
501 
spl_fixpt_truncate(struct spl_fixed31_32 arg,unsigned int frac_bits)502 static inline struct spl_fixed31_32 spl_fixpt_truncate(struct spl_fixed31_32 arg, unsigned int frac_bits)
503 {
504 	bool negative = arg.value < 0;
505 
506 	if (frac_bits >= FIXED31_32_BITS_PER_FRACTIONAL_PART) {
507 		ASSERT(frac_bits == FIXED31_32_BITS_PER_FRACTIONAL_PART);
508 		return arg;
509 	}
510 
511 	if (negative)
512 		arg.value = -arg.value;
513 	arg.value &= (~0ULL) << (FIXED31_32_BITS_PER_FRACTIONAL_PART - frac_bits);
514 	if (negative)
515 		arg.value = -arg.value;
516 	return arg;
517 }
518 
519 struct spl_fixed31_32 spl_fixpt_from_ux_dy(unsigned int value, unsigned int integer_bits, unsigned int fractional_bits);
520 struct spl_fixed31_32 spl_fixpt_from_int_dy(unsigned int int_value,
521 		unsigned int frac_value,
522 		unsigned int integer_bits,
523 		unsigned int fractional_bits);
524 
525 #endif
526