xref: /linux/drivers/gpu/drm/amd/display/dc/spl/spl_custom_float.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2024 Advanced Micro Devices, Inc.
4 
5 #include "spl_debug.h"
6 #include "spl_custom_float.h"
7 
spl_build_custom_float(struct spl_fixed31_32 value,const struct spl_custom_float_format * format,bool * negative,uint32_t * mantissa,uint32_t * exponenta)8 static bool spl_build_custom_float(struct spl_fixed31_32 value,
9 			       const struct spl_custom_float_format *format,
10 			       bool *negative,
11 			       uint32_t *mantissa,
12 			       uint32_t *exponenta)
13 {
14 	uint32_t exp_offset = (1 << (format->exponenta_bits - 1)) - 1;
15 
16 	const struct spl_fixed31_32 mantissa_constant_plus_max_fraction =
17 		spl_fixpt_from_fraction((1LL << (format->mantissa_bits + 1)) - 1,
18 				       1LL << format->mantissa_bits);
19 
20 	struct spl_fixed31_32 mantiss;
21 
22 	if (spl_fixpt_eq(value, spl_fixpt_zero)) {
23 		*negative = false;
24 		*mantissa = 0;
25 		*exponenta = 0;
26 		return true;
27 	}
28 
29 	if (spl_fixpt_lt(value, spl_fixpt_zero)) {
30 		*negative = format->sign;
31 		value = spl_fixpt_neg(value);
32 	} else {
33 		*negative = false;
34 	}
35 
36 	if (spl_fixpt_lt(value, spl_fixpt_one)) {
37 		uint32_t i = 1;
38 
39 		do {
40 			value = spl_fixpt_shl(value, 1);
41 			++i;
42 		} while (spl_fixpt_lt(value, spl_fixpt_one));
43 
44 		--i;
45 
46 		if (exp_offset <= i) {
47 			*mantissa = 0;
48 			*exponenta = 0;
49 			return true;
50 		}
51 
52 		*exponenta = exp_offset - i;
53 	} else if (spl_fixpt_le(mantissa_constant_plus_max_fraction, value)) {
54 		uint32_t i = 1;
55 
56 		do {
57 			value = spl_fixpt_shr(value, 1);
58 			++i;
59 		} while (spl_fixpt_lt(mantissa_constant_plus_max_fraction, value));
60 
61 		*exponenta = exp_offset + i - 1;
62 	} else {
63 		*exponenta = exp_offset;
64 	}
65 
66 	mantiss = spl_fixpt_sub(value, spl_fixpt_one);
67 
68 	if (spl_fixpt_lt(mantiss, spl_fixpt_zero) ||
69 	    spl_fixpt_lt(spl_fixpt_one, mantiss))
70 		mantiss = spl_fixpt_zero;
71 	else
72 		mantiss = spl_fixpt_shl(mantiss, format->mantissa_bits);
73 
74 	*mantissa = spl_fixpt_floor(mantiss);
75 
76 	return true;
77 }
78 
spl_setup_custom_float(const struct spl_custom_float_format * format,bool negative,uint32_t mantissa,uint32_t exponenta,uint32_t * result)79 static bool spl_setup_custom_float(const struct spl_custom_float_format *format,
80 			       bool negative,
81 			       uint32_t mantissa,
82 			       uint32_t exponenta,
83 			       uint32_t *result)
84 {
85 	uint32_t i = 0;
86 	uint32_t j = 0;
87 	uint32_t value = 0;
88 
89 	/* verification code:
90 	 * once calculation is ok we can remove it
91 	 */
92 
93 	const uint32_t mantissa_mask =
94 		(1 << (format->mantissa_bits + 1)) - 1;
95 
96 	const uint32_t exponenta_mask =
97 		(1 << (format->exponenta_bits + 1)) - 1;
98 
99 	if (mantissa & ~mantissa_mask) {
100 		SPL_BREAK_TO_DEBUGGER();
101 		mantissa = mantissa_mask;
102 	}
103 
104 	if (exponenta & ~exponenta_mask) {
105 		SPL_BREAK_TO_DEBUGGER();
106 		exponenta = exponenta_mask;
107 	}
108 
109 	/* end of verification code */
110 
111 	while (i < format->mantissa_bits) {
112 		uint32_t mask = 1 << i;
113 
114 		if (mantissa & mask)
115 			value |= mask;
116 
117 		++i;
118 	}
119 
120 	while (j < format->exponenta_bits) {
121 		uint32_t mask = 1 << j;
122 
123 		if (exponenta & mask)
124 			value |= mask << i;
125 
126 		++j;
127 	}
128 
129 	if (negative && format->sign)
130 		value |= 1 << (i + j);
131 
132 	*result = value;
133 
134 	return true;
135 }
136 
spl_convert_to_custom_float_format(struct spl_fixed31_32 value,const struct spl_custom_float_format * format,uint32_t * result)137 bool spl_convert_to_custom_float_format(struct spl_fixed31_32 value,
138 				    const struct spl_custom_float_format *format,
139 				    uint32_t *result)
140 {
141 	uint32_t mantissa;
142 	uint32_t exponenta;
143 	bool negative;
144 
145 	return spl_build_custom_float(value, format, &negative, &mantissa, &exponenta) &&
146 				  spl_setup_custom_float(format,
147 						     negative,
148 						     mantissa,
149 						     exponenta,
150 						     result);
151 }
152