upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / media / video / samsung / mali / common / mali_osk_bitops.h
1 /*
2  * Copyright (C) 2010 ARM Limited. All rights reserved.
3  * 
4  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6  * 
7  * A copy of the licence is included with the program, and can also be obtained from Free Software
8  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
9  */
10
11 /**
12  * @file mali_osk_bitops.h
13  * Implementation of the OS abstraction layer for the kernel device driver
14  */
15
16 #ifndef __MALI_OSK_BITOPS_H__
17 #define __MALI_OSK_BITOPS_H__
18
19 #ifdef __cplusplus
20 extern "C"
21 {
22 #endif
23
24 MALI_STATIC_INLINE void _mali_internal_clear_bit( u32 bit, u32 *addr )
25 {
26         MALI_DEBUG_ASSERT( bit < 32 );
27         MALI_DEBUG_ASSERT( NULL != addr );
28
29         (*addr) &= ~(1 << bit);
30 }
31
32 MALI_STATIC_INLINE void _mali_internal_set_bit( u32 bit, u32 *addr )
33 {
34         MALI_DEBUG_ASSERT( bit < 32 );
35         MALI_DEBUG_ASSERT( NULL != addr );
36
37         (*addr) |= (1 << bit);
38 }
39
40 MALI_STATIC_INLINE u32 _mali_internal_test_bit( u32 bit, u32 value )
41 {
42         MALI_DEBUG_ASSERT( bit < 32 );
43         return value & (1 << bit);
44 }
45
46 MALI_STATIC_INLINE int _mali_internal_find_first_zero_bit( u32 value )
47 {
48         u32 inverted;
49         u32 negated;
50         u32 isolated;
51         u32 leading_zeros;
52
53         /* Begin with xxx...x0yyy...y, where ys are 1, number of ys is in range  0..31 */
54         inverted = ~value; /* zzz...z1000...0 */
55         /* Using count_trailing_zeros on inverted value -
56          * See ARM System Developers Guide for details of count_trailing_zeros */
57
58         /* Isolate the zero: it is preceeded by a run of 1s, so add 1 to it */
59         negated = (u32)-inverted ; /* -a == ~a + 1 (mod 2^n) for n-bit numbers */
60     /* negated = xxx...x1000...0 */
61
62         isolated = negated & inverted ; /* xxx...x1000...0 & zzz...z1000...0, zs are ~xs */
63         /* And so the first zero bit is in the same position as the 1 == number of 1s that preceeded it
64          * Note that the output is zero if value was all 1s */
65
66         leading_zeros = _mali_osk_clz( isolated );
67
68         return 31 - leading_zeros;
69 }
70
71
72 /** @defgroup _mali_osk_bitops OSK Non-atomic Bit-operations
73  * @{ */
74
75 /**
76  * These bit-operations do not work atomically, and so locks must be used if
77  * atomicity is required.
78  *
79  * Reference implementations for Little Endian are provided, and so it should
80  * not normally be necessary to re-implement these. Efficient bit-twiddling
81  * techniques are used where possible, implemented in portable C.
82  *
83  * Note that these reference implementations rely on _mali_osk_clz() being
84  * implemented.
85  */
86
87 /** @brief Clear a bit in a sequence of 32-bit words
88  * @param nr bit number to clear, starting from the (Little-endian) least
89  * significant bit
90  * @param addr starting point for counting.
91  */
92 MALI_STATIC_INLINE void _mali_osk_clear_nonatomic_bit( u32 nr, u32 *addr )
93 {
94         addr += nr >> 5; /* find the correct word */
95         nr = nr & ((1 << 5)-1); /* The bit number within the word */
96
97         _mali_internal_clear_bit( nr, addr );
98 }
99
100 /** @brief Set a bit in a sequence of 32-bit words
101  * @param nr bit number to set, starting from the (Little-endian) least
102  * significant bit
103  * @param addr starting point for counting.
104  */
105 MALI_STATIC_INLINE void _mali_osk_set_nonatomic_bit( u32 nr, u32 *addr )
106 {
107         addr += nr >> 5; /* find the correct word */
108         nr = nr & ((1 << 5)-1); /* The bit number within the word */
109
110         _mali_internal_set_bit( nr, addr );
111 }
112
113 /** @brief Test a bit in a sequence of 32-bit words
114  * @param nr bit number to test, starting from the (Little-endian) least
115  * significant bit
116  * @param addr starting point for counting.
117  * @return zero if bit was clear, non-zero if set. Do not rely on the return
118  * value being related to the actual word under test.
119  */
120 MALI_STATIC_INLINE u32 _mali_osk_test_bit( u32 nr, u32 *addr )
121 {
122         addr += nr >> 5; /* find the correct word */
123         nr = nr & ((1 << 5)-1); /* The bit number within the word */
124
125         return _mali_internal_test_bit( nr, *addr );
126 }
127
128 /* Return maxbit if not found */
129 /** @brief Find the first zero bit in a sequence of 32-bit words
130  * @param addr starting point for search.
131  * @param maxbit the maximum number of bits to search
132  * @return the number of the first zero bit found, or maxbit if none were found
133  * in the specified range.
134  */
135 MALI_STATIC_INLINE u32 _mali_osk_find_first_zero_bit( const u32 *addr, u32 maxbit )
136 {
137         u32 total;
138
139         for ( total = 0; total < maxbit; total += 32, ++addr )
140         {
141                 int result;
142                 result = _mali_internal_find_first_zero_bit( *addr );
143
144                 /* non-negative signifies the bit was found */
145                 if ( result >= 0 )
146                 {
147                         total += (u32)result;
148                         break;
149                 }
150         }
151
152         /* Now check if we reached maxbit or above */
153         if ( total >= maxbit )
154         {
155                 total = maxbit;
156         }
157
158         return total; /* either the found bit nr, or maxbit if not found */
159 }
160 /** @} */ /* end group _mali_osk_bitops */
161
162 #ifdef __cplusplus
163 }
164 #endif
165
166 #endif /* __MALI_OSK_BITOPS_H__ */