brintos

brintos / linux-shallow public Read only

0
0
Text · 5.3 KiB · 1922188 Raw
242 lines · c
1/*2 * Copyright 2009 Red Hat Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * 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 OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: Dave Airlie23 *          Christian König24 */25#ifndef DRM_FIXED_H26#define DRM_FIXED_H27 28#include <linux/math64.h>29#include <linux/types.h>30#include <linux/wordpart.h>31 32typedef union dfixed {33	u32 full;34} fixed20_12;35 36 37#define dfixed_const(A) (u32)(((A) << 12))/*  + ((B + 0.000122)*4096)) */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 47static inline u32 dfixed_floor(fixed20_12 A)48{49	u32 non_frac = dfixed_trunc(A);50 51	return dfixed_const(non_frac);52}53 54static 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	else61		return dfixed_const(non_frac);62}63 64static 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		3275#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	1LL79#define DRM_FIXED_ALMOST_ONE	(DRM_FIXED_ONE - DRM_FIXED_EPSILON)80 81static inline s64 drm_int2fixp(int a)82{83	return ((s64)a) << DRM_FIXED_POINT;84}85 86static inline int drm_fixp2int(s64 a)87{88	return ((s64)a) >> DRM_FIXED_POINT;89}90 91static inline int drm_fixp2int_round(s64 a)92{93	return drm_fixp2int(a + DRM_FIXED_ONE / 2);94}95 96static inline int drm_fixp2int_ceil(s64 a)97{98	if (a >= 0)99		return drm_fixp2int(a + DRM_FIXED_ALMOST_ONE);100	else101		return drm_fixp2int(a - DRM_FIXED_ALMOST_ONE);102}103 104static inline unsigned drm_fixp_msbset(s64 a)105{106	unsigned shift, sign = (a >> 63) & 1;107 108	for (shift = 62; shift > 0; --shift)109		if (((a >> shift) & 1) != sign)110			return shift;111 112	return 0;113}114 115static inline s64 drm_fixp_mul(s64 a, s64 b)116{117	unsigned shift = drm_fixp_msbset(a) + drm_fixp_msbset(b);118	s64 result;119 120	if (shift > 61) {121		shift = shift - 61;122		a >>= (shift >> 1) + (shift & 1);123		b >>= shift >> 1;124	} else125		shift = 0;126 127	result = a * b;128 129	if (shift > DRM_FIXED_POINT)130		return result << (shift - DRM_FIXED_POINT);131 132	if (shift < DRM_FIXED_POINT)133		return result >> (DRM_FIXED_POINT - shift);134 135	return result;136}137 138static inline s64 drm_fixp_div(s64 a, s64 b)139{140	unsigned shift = 62 - drm_fixp_msbset(a);141	s64 result;142 143	a <<= shift;144 145	if (shift < DRM_FIXED_POINT)146		b >>= (DRM_FIXED_POINT - shift);147 148	result = div64_s64(a, b);149 150	if (shift > DRM_FIXED_POINT)151		return result >> (shift - DRM_FIXED_POINT);152 153	return result;154}155 156static inline s64 drm_fixp_from_fraction(s64 a, s64 b)157{158	s64 res;159	bool a_neg = a < 0;160	bool b_neg = b < 0;161	u64 a_abs = a_neg ? -a : a;162	u64 b_abs = b_neg ? -b : b;163	u64 rem;164 165	/* determine integer part */166	u64 res_abs  = div64_u64_rem(a_abs, b_abs, &rem);167 168	/* determine fractional part */169	{170		u32 i = DRM_FIXED_POINT;171 172		do {173			rem <<= 1;174			res_abs <<= 1;175			if (rem >= b_abs) {176				res_abs |= 1;177				rem -= b_abs;178			}179		} while (--i != 0);180	}181 182	/* round up LSB */183	{184		u64 summand = (rem << 1) >= b_abs;185 186		res_abs += summand;187	}188 189	res = (s64) res_abs;190	if (a_neg ^ b_neg)191		res = -res;192	return res;193}194 195static inline s64 drm_fixp_exp(s64 x)196{197	s64 tolerance = div64_s64(DRM_FIXED_ONE, 1000000);198	s64 sum = DRM_FIXED_ONE, term, y = x;199	u64 count = 1;200 201	if (x < 0)202		y = -1 * x;203 204	term = y;205 206	while (term >= tolerance) {207		sum = sum + term;208		count = count + 1;209		term = drm_fixp_mul(term, div64_s64(y, count));210	}211 212	if (x < 0)213		sum = drm_fixp_div(DRM_FIXED_ONE, sum);214 215	return sum;216}217 218static inline int fxp_q4_from_int(int val_int)219{220	return val_int << 4;221}222 223static inline int fxp_q4_to_int(int val_q4)224{225	return val_q4 >> 4;226}227 228static inline int fxp_q4_to_int_roundup(int val_q4)229{230	return (val_q4 + 0xf) >> 4;231}232 233static inline int fxp_q4_to_frac(int val_q4)234{235	return val_q4 & 0xf;236}237 238#define FXP_Q4_FMT		"%d.%04d"239#define FXP_Q4_ARGS(val_q4)	fxp_q4_to_int(val_q4), (fxp_q4_to_frac(val_q4) * 625)240 241#endif242