| 1 | |
| 2 | * Copyright 2009 Red Hat Inc.
|
| 3 | *
|
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a
|
| 5 | * copy of this software and associated documentation files (the "Software"),
|
| 6 | * to deal in the Software without restriction, including without limitation
|
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
| 8 | * and/or sell copies of the Software, and to permit persons to whom the
|
| 9 | * Software is furnished to do so, subject to the following conditions:
|
| 10 | *
|
| 11 | * The above copyright notice and this permission notice shall be included in
|
| 12 | * all copies or substantial portions of the Software.
|
| 13 | *
|
| 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
| 17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
| 18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
| 19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
| 20 | * OTHER DEALINGS IN THE SOFTWARE.
|
| 21 | *
|
| 22 | * Authors: Dave Airlie
|
| 23 | * Christian König
|
| 24 |
|
| 25 | #ifndef DRM_FIXED_H
|
| 26 | #define DRM_FIXED_H
|
| 27 |
|
| 28 | #include <linux/math64.h>
|
| 29 | #include <linux/types.h>
|
| 30 | #include <linux/wordpart.h>
|
| 31 |
|
| 32 | typedef union dfixed {
|
| 33 | u32 full;
|
| 34 | } fixed20_12;
|
| 35 |
|
| 36 |
|
| 37 | #define dfixed_const(A) (u32)(((A) << 12))
|
| 38 | #define dfixed_const_half(A) (u32)(((A) << 12) + 2048)
|
| 39 | #define dfixed_const_666(A) (u32)(((A) << 12) + 2731)
|
| 40 | #define dfixed_const_8(A) (u32)(((A) << 12) + 3277)
|
| 41 | #define dfixed_mul(A, B) ((u64)((u64)(A).full * (B).full + 2048) >> 12)
|
| 42 | #define dfixed_init(A) { .full = dfixed_const((A)) }
|
| 43 | #define dfixed_init_half(A) { .full = dfixed_const_half((A)) }
|
| 44 | #define dfixed_trunc(A) ((A).full >> 12)
|
| 45 | #define dfixed_frac(A) ((A).full & ((1 << 12) - 1))
|
| 46 |
|
| 47 | static inline u32 dfixed_floor(fixed20_12 A)
|
| 48 | {
|
| 49 | u32 non_frac = dfixed_trunc(A);
|
| 50 |
|
| 51 | return dfixed_const(non_frac);
|
| 52 | }
|
| 53 |
|
| 54 | static inline u32 dfixed_ceil(fixed20_12 A)
|
| 55 | {
|
| 56 | u32 non_frac = dfixed_trunc(A);
|
| 57 |
|
| 58 | if (A.full > dfixed_const(non_frac))
|
| 59 | return dfixed_const(non_frac + 1);
|
| 60 | else
|
| 61 | return dfixed_const(non_frac);
|
| 62 | }
|
| 63 |
|
| 64 | static inline u32 dfixed_div(fixed20_12 A, fixed20_12 B)
|
| 65 | {
|
| 66 | u64 tmp = ((u64)A.full << 13);
|
| 67 |
|
| 68 | do_div(tmp, B.full);
|
| 69 | tmp += 1;
|
| 70 | tmp /= 2;
|
| 71 | return lower_32_bits(tmp);
|
| 72 | }
|
| 73 |
|
| 74 | #define DRM_FIXED_POINT 32
|
| 75 | #define DRM_FIXED_ONE (1ULL << DRM_FIXED_POINT)
|
| 76 | #define DRM_FIXED_DECIMAL_MASK (DRM_FIXED_ONE - 1)
|
| 77 | #define DRM_FIXED_DIGITS_MASK (~DRM_FIXED_DECIMAL_MASK)
|
| 78 | #define DRM_FIXED_EPSILON 1LL
|
| 79 | #define DRM_FIXED_ALMOST_ONE (DRM_FIXED_ONE - DRM_FIXED_EPSILON)
|
| 80 |
|
| 81 | |
| 82 | * drm_sm2fixp() - convert signed-magnitude to fixed point
|
| 83 | * @a: 1.31.32 signed-magnitude fixed point
|
| 84 | *
|
| 85 | * Convert a 1.31.32 signed-magnitude fixed point to 32.32
|
| 86 | * 2s-complement fixed point
|
| 87 | *
|
| 88 | * @return s64 2s-complement fixed point
|
| 89 |
|
| 90 | static inline s64 drm_sm2fixp(__u64 a)
|
| 91 | {
|
| 92 | if ((a & (1LL << 63))) {
|
| 93 | return -(a & 0x7fffffffffffffffll);
|
| 94 | } else {
|
| 95 | return a;
|
| 96 | }
|
| 97 | }
|
| 98 |
|
| 99 | static inline s64 drm_int2fixp(int a)
|
| 100 | {
|
| 101 | return ((s64)a) << DRM_FIXED_POINT;
|
| 102 | }
|
| 103 |
|
| 104 | static inline int drm_fixp2int(s64 a)
|
| 105 | {
|
| 106 | return ((s64)a) >> DRM_FIXED_POINT;
|
| 107 | }
|
| 108 |
|
| 109 | static inline int drm_fixp2int_round(s64 a)
|
| 110 | {
|
| 111 | return drm_fixp2int(a + DRM_FIXED_ONE / 2);
|
| 112 | }
|
| 113 |
|
| 114 | static inline int drm_fixp2int_ceil(s64 a)
|
| 115 | {
|
| 116 | if (a >= 0)
|
| 117 | return drm_fixp2int(a + DRM_FIXED_ALMOST_ONE);
|
| 118 | else
|
| 119 | return drm_fixp2int(a - DRM_FIXED_ALMOST_ONE);
|
| 120 | }
|
| 121 |
|
| 122 | static inline unsigned drm_fixp_msbset(s64 a)
|
| 123 | {
|
| 124 | unsigned shift, sign = (a >> 63) & 1;
|
| 125 |
|
| 126 | for (shift = 62; shift > 0; --shift)
|
| 127 | if (((a >> shift) & 1) != sign)
|
| 128 | return shift;
|
| 129 |
|
| 130 | return 0;
|
| 131 | }
|
| 132 |
|
| 133 | static inline s64 drm_fixp_mul(s64 a, s64 b)
|
| 134 | {
|
| 135 | unsigned shift = drm_fixp_msbset(a) + drm_fixp_msbset(b);
|
| 136 | s64 result;
|
| 137 |
|
| 138 | if (shift > 61) {
|
| 139 | shift = shift - 61;
|
| 140 | a >>= (shift >> 1) + (shift & 1);
|
| 141 | b >>= shift >> 1;
|
| 142 | } else
|
| 143 | shift = 0;
|
| 144 |
|
| 145 | result = a * b;
|
| 146 |
|
| 147 | if (shift > DRM_FIXED_POINT)
|
| 148 | return result << (shift - DRM_FIXED_POINT);
|
| 149 |
|
| 150 | if (shift < DRM_FIXED_POINT)
|
| 151 | return result >> (DRM_FIXED_POINT - shift);
|
| 152 |
|
| 153 | return result;
|
| 154 | }
|
| 155 |
|
| 156 | static inline s64 drm_fixp_div(s64 a, s64 b)
|
| 157 | {
|
| 158 | unsigned shift = 62 - drm_fixp_msbset(a);
|
| 159 | s64 result;
|
| 160 |
|
| 161 | a <<= shift;
|
| 162 |
|
| 163 | if (shift < DRM_FIXED_POINT)
|
| 164 | b >>= (DRM_FIXED_POINT - shift);
|
| 165 |
|
| 166 | result = div64_s64(a, b);
|
| 167 |
|
| 168 | if (shift > DRM_FIXED_POINT)
|
| 169 | return result >> (shift - DRM_FIXED_POINT);
|
| 170 |
|
| 171 | return result;
|
| 172 | }
|
| 173 |
|
| 174 | static inline s64 drm_fixp_from_fraction(s64 a, s64 b)
|
| 175 | {
|
| 176 | s64 res;
|
| 177 | bool a_neg = a < 0;
|
| 178 | bool b_neg = b < 0;
|
| 179 | u64 a_abs = a_neg ? -a : a;
|
| 180 | u64 b_abs = b_neg ? -b : b;
|
| 181 | u64 rem;
|
| 182 |
|
| 183 |
|
| 184 | u64 res_abs = div64_u64_rem(a_abs, b_abs, &rem);
|
| 185 |
|
| 186 |
|
| 187 | {
|
| 188 | u32 i = DRM_FIXED_POINT;
|
| 189 |
|
| 190 | do {
|
| 191 | rem <<= 1;
|
| 192 | res_abs <<= 1;
|
| 193 | if (rem >= b_abs) {
|
| 194 | res_abs |= 1;
|
| 195 | rem -= b_abs;
|
| 196 | }
|
| 197 | } while (--i != 0);
|
| 198 | }
|
| 199 |
|
| 200 |
|
| 201 | {
|
| 202 | u64 summand = (rem << 1) >= b_abs;
|
| 203 |
|
| 204 | res_abs += summand;
|
| 205 | }
|
| 206 |
|
| 207 | res = (s64) res_abs;
|
| 208 | if (a_neg ^ b_neg)
|
| 209 | res = -res;
|
| 210 | return res;
|
| 211 | }
|
| 212 |
|
| 213 | static inline s64 drm_fixp_exp(s64 x)
|
| 214 | {
|
| 215 | s64 tolerance = div64_s64(DRM_FIXED_ONE, 1000000);
|
| 216 | s64 sum = DRM_FIXED_ONE, term, y = x;
|
| 217 | u64 count = 1;
|
| 218 |
|
| 219 | if (x < 0)
|
| 220 | y = -1 * x;
|
| 221 |
|
| 222 | term = y;
|
| 223 |
|
| 224 | while (term >= tolerance) {
|
| 225 | sum = sum + term;
|
| 226 | count = count + 1;
|
| 227 | term = drm_fixp_mul(term, div64_s64(y, count));
|
| 228 | }
|
| 229 |
|
| 230 | if (x < 0)
|
| 231 | sum = drm_fixp_div(DRM_FIXED_ONE, sum);
|
| 232 |
|
| 233 | return sum;
|
| 234 | }
|
| 235 |
|
| 236 | static inline int fxp_q4_from_int(int val_int)
|
| 237 | {
|
| 238 | return val_int << 4;
|
| 239 | }
|
| 240 |
|
| 241 | static inline int fxp_q4_to_int(int val_q4)
|
| 242 | {
|
| 243 | return val_q4 >> 4;
|
| 244 | }
|
| 245 |
|
| 246 | static inline int fxp_q4_to_int_roundup(int val_q4)
|
| 247 | {
|
| 248 | return (val_q4 + 0xf) >> 4;
|
| 249 | }
|
| 250 |
|
| 251 | static inline int fxp_q4_to_frac(int val_q4)
|
| 252 | {
|
| 253 | return val_q4 & 0xf;
|
| 254 | }
|
| 255 |
|
| 256 | #define FXP_Q4_FMT "%d.%04d"
|
| 257 | #define FXP_Q4_ARGS(val_q4) fxp_q4_to_int(val_q4), (fxp_q4_to_frac(val_q4) * 625)
|
| 258 |
|
| 259 | #endif
|