aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Deucher <alexander.deucher@amd.com>2013-03-22 10:35:50 -0400
committerAlex Deucher <alexander.deucher@amd.com>2013-06-27 19:16:37 -0400
commit210a0b9e212370ed8c2784c2115e7ff4bb1259bd (patch)
tree35efeaaa2b97e7f4e0a9fe3475967bd859cf55d6
parent9ed36f750534e2c6533fcbf32df89cf20cf87e91 (diff)
drm: add some additional fixed point helpers (v3)
Required for certain driver calculations. Code was written by Christian König and ported to the drm by me. v2: fix 64 bit divides v3: fix 64 bit for real (math64.h) Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--include/drm/drm_fixed.h94
1 files changed, 94 insertions, 0 deletions
diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h
index 0ead502e17d2..f5e1168c7647 100644
--- a/include/drm/drm_fixed.h
+++ b/include/drm/drm_fixed.h
@@ -20,10 +20,13 @@
20 * OTHER DEALINGS IN THE SOFTWARE. 20 * OTHER DEALINGS IN THE SOFTWARE.
21 * 21 *
22 * Authors: Dave Airlie 22 * Authors: Dave Airlie
23 * Christian König
23 */ 24 */
24#ifndef DRM_FIXED_H 25#ifndef DRM_FIXED_H
25#define DRM_FIXED_H 26#define DRM_FIXED_H
26 27
28#include <linux/math64.h>
29
27typedef union dfixed { 30typedef union dfixed {
28 u32 full; 31 u32 full;
29} fixed20_12; 32} fixed20_12;
@@ -65,4 +68,95 @@ static inline u32 dfixed_div(fixed20_12 A, fixed20_12 B)
65 tmp /= 2; 68 tmp /= 2;
66 return lower_32_bits(tmp); 69 return lower_32_bits(tmp);
67} 70}
71
72#define DRM_FIXED_POINT 32
73#define DRM_FIXED_ONE (1ULL << DRM_FIXED_POINT)
74#define DRM_FIXED_DECIMAL_MASK (DRM_FIXED_ONE - 1)
75#define DRM_FIXED_DIGITS_MASK (~DRM_FIXED_DECIMAL_MASK)
76
77static inline s64 drm_int2fixp(int a)
78{
79 return ((s64)a) << DRM_FIXED_POINT;
80}
81
82static inline int drm_fixp2int(int64_t a)
83{
84 return ((s64)a) >> DRM_FIXED_POINT;
85}
86
87static inline s64 drm_fixp_msbset(int64_t a)
88{
89 unsigned shift, sign = (a >> 63) & 1;
90
91 for (shift = 62; shift > 0; --shift)
92 if ((a >> shift) != sign)
93 return shift;
94
95 return 0;
96}
97
98static inline s64 drm_fixp_mul(s64 a, s64 b)
99{
100 unsigned shift = drm_fixp_msbset(a) + drm_fixp_msbset(b);
101 s64 result;
102
103 if (shift > 63) {
104 shift = shift - 63;
105 a >>= shift >> 1;
106 b >>= shift >> 1;
107 } else
108 shift = 0;
109
110 result = a * b;
111
112 if (shift > DRM_FIXED_POINT)
113 return result << (shift - DRM_FIXED_POINT);
114
115 if (shift < DRM_FIXED_POINT)
116 return result >> (DRM_FIXED_POINT - shift);
117
118 return result;
119}
120
121static inline s64 drm_fixp_div(s64 a, s64 b)
122{
123 unsigned shift = 63 - drm_fixp_msbset(a);
124 s64 result;
125
126 a <<= shift;
127
128 if (shift < DRM_FIXED_POINT)
129 b >>= (DRM_FIXED_POINT - shift);
130
131 result = div64_s64(a, b);
132
133 if (shift > DRM_FIXED_POINT)
134 return result >> (shift - DRM_FIXED_POINT);
135
136 return result;
137}
138
139static inline s64 drm_fixp_exp(s64 x)
140{
141 s64 tolerance = div64_s64(DRM_FIXED_ONE, 1000000);
142 s64 sum = DRM_FIXED_ONE, term, y = x;
143 u64 count = 1;
144
145 if (x < 0)
146 y = -1 * x;
147
148 term = y;
149
150 while (term >= tolerance) {
151 sum = sum + term;
152 count = count + 1;
153 term = drm_fixp_mul(term, div64_s64(y, count));
154 }
155
156 if (x < 0)
157 sum = drm_fixp_div(1, sum);
158
159 return sum;
160}
161
68#endif 162#endif