blob: 6cde6dbfdef2636c6f8d0094c4d60f72dcaf2855 [file] [log] [blame]
Wolfgang Denk6cb142f2006-03-12 02:12:27 +01001/*
2 * U-boot - bitops.h Routines for bit operations
3 *
Aubrey Li155fd762007-04-05 18:31:18 +08004 * Copyright (c) 2005-2007 Analog Devices Inc.
Wolfgang Denk6cb142f2006-03-12 02:12:27 +01005 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02006 * SPDX-License-Identifier: GPL-2.0+
Wolfgang Denk6cb142f2006-03-12 02:12:27 +01007 */
8
9#ifndef _BLACKFIN_BITOPS_H
10#define _BLACKFIN_BITOPS_H
11
12/*
13 * Copyright 1992, Linus Torvalds.
14 */
15
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010016#include <asm/byteorder.h>
17#include <asm/system.h>
Fabio Estevam9b0e3fd2015-11-05 12:43:27 -020018#include <asm-generic/bitops/fls.h>
19#include <asm-generic/bitops/__fls.h>
20#include <asm-generic/bitops/fls64.h>
21#include <asm-generic/bitops/__ffs.h>
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010022
23#ifdef __KERNEL__
24/*
25 * Function prototypes to keep gcc -Wall happy
26 */
27
28/*
29 * The __ functions are not atomic
30 */
31
32/*
33 * ffz = Find First Zero in word. Undefined if no zero exists,
34 * so code should check against ~0UL first..
35 */
36static __inline__ unsigned long ffz(unsigned long word)
37{
38 unsigned long result = 0;
39
40 while (word & 1) {
41 result++;
42 word >>= 1;
43 }
44 return result;
45}
46
47static __inline__ void set_bit(int nr, volatile void *addr)
48{
Aubrey.Li3f0606a2007-03-09 13:38:44 +080049 int *a = (int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010050 int mask;
51 unsigned long flags;
52
53 a += nr >> 5;
54 mask = 1 << (nr & 0x1f);
Mike Frysingerd4d77302008-02-04 19:26:55 -050055 local_irq_save(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010056 *a |= mask;
Mike Frysingerd4d77302008-02-04 19:26:55 -050057 local_irq_restore(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010058}
59
60static __inline__ void __set_bit(int nr, volatile void *addr)
61{
Aubrey.Li3f0606a2007-03-09 13:38:44 +080062 int *a = (int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010063 int mask;
64
65 a += nr >> 5;
66 mask = 1 << (nr & 0x1f);
67 *a |= mask;
68}
Simon Kagstrom0413cfe2009-09-17 15:15:52 +020069#define PLATFORM__SET_BIT
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010070
71/*
72 * clear_bit() doesn't provide any barrier for the compiler.
73 */
74#define smp_mb__before_clear_bit() barrier()
75#define smp_mb__after_clear_bit() barrier()
76
77static __inline__ void clear_bit(int nr, volatile void *addr)
78{
Aubrey.Li3f0606a2007-03-09 13:38:44 +080079 int *a = (int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010080 int mask;
81 unsigned long flags;
82
83 a += nr >> 5;
84 mask = 1 << (nr & 0x1f);
Mike Frysingerd4d77302008-02-04 19:26:55 -050085 local_irq_save(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010086 *a &= ~mask;
Mike Frysingerd4d77302008-02-04 19:26:55 -050087 local_irq_restore(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010088}
89
90static __inline__ void change_bit(int nr, volatile void *addr)
91{
92 int mask, flags;
Aubrey.Li3f0606a2007-03-09 13:38:44 +080093 unsigned long *ADDR = (unsigned long *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010094
95 ADDR += nr >> 5;
96 mask = 1 << (nr & 31);
Mike Frysingerd4d77302008-02-04 19:26:55 -050097 local_irq_save(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010098 *ADDR ^= mask;
Mike Frysingerd4d77302008-02-04 19:26:55 -050099 local_irq_restore(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100100}
101
102static __inline__ void __change_bit(int nr, volatile void *addr)
103{
104 int mask;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800105 unsigned long *ADDR = (unsigned long *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100106
107 ADDR += nr >> 5;
108 mask = 1 << (nr & 31);
109 *ADDR ^= mask;
110}
111
112static __inline__ int test_and_set_bit(int nr, volatile void *addr)
113{
114 int mask, retval;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800115 volatile unsigned int *a = (volatile unsigned int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100116 unsigned long flags;
117
118 a += nr >> 5;
119 mask = 1 << (nr & 0x1f);
Mike Frysingerd4d77302008-02-04 19:26:55 -0500120 local_irq_save(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100121 retval = (mask & *a) != 0;
122 *a |= mask;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500123 local_irq_restore(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100124
125 return retval;
126}
127
128static __inline__ int __test_and_set_bit(int nr, volatile void *addr)
129{
130 int mask, retval;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800131 volatile unsigned int *a = (volatile unsigned int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100132
133 a += nr >> 5;
134 mask = 1 << (nr & 0x1f);
135 retval = (mask & *a) != 0;
136 *a |= mask;
137 return retval;
138}
139
140static __inline__ int test_and_clear_bit(int nr, volatile void *addr)
141{
142 int mask, retval;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800143 volatile unsigned int *a = (volatile unsigned int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100144 unsigned long flags;
145
146 a += nr >> 5;
147 mask = 1 << (nr & 0x1f);
Mike Frysingerd4d77302008-02-04 19:26:55 -0500148 local_irq_save(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100149 retval = (mask & *a) != 0;
150 *a &= ~mask;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500151 local_irq_restore(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100152
153 return retval;
154}
155
156static __inline__ int __test_and_clear_bit(int nr, volatile void *addr)
157{
158 int mask, retval;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800159 volatile unsigned int *a = (volatile unsigned int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100160
161 a += nr >> 5;
162 mask = 1 << (nr & 0x1f);
163 retval = (mask & *a) != 0;
164 *a &= ~mask;
165 return retval;
166}
167
168static __inline__ int test_and_change_bit(int nr, volatile void *addr)
169{
170 int mask, retval;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800171 volatile unsigned int *a = (volatile unsigned int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100172 unsigned long flags;
173
174 a += nr >> 5;
175 mask = 1 << (nr & 0x1f);
Mike Frysingerd4d77302008-02-04 19:26:55 -0500176 local_irq_save(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100177 retval = (mask & *a) != 0;
178 *a ^= mask;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500179 local_irq_restore(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100180
181 return retval;
182}
183
184static __inline__ int __test_and_change_bit(int nr, volatile void *addr)
185{
186 int mask, retval;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800187 volatile unsigned int *a = (volatile unsigned int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100188
189 a += nr >> 5;
190 mask = 1 << (nr & 0x1f);
191 retval = (mask & *a) != 0;
192 *a ^= mask;
193 return retval;
194}
195
196/*
197 * This routine doesn't need to be atomic.
198 */
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800199static __inline__ int __constant_test_bit(int nr, const volatile void *addr)
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100200{
201 return ((1UL << (nr & 31)) &
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800202 (((const volatile unsigned int *)addr)[nr >> 5])) != 0;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100203}
204
205static __inline__ int __test_bit(int nr, volatile void *addr)
206{
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800207 int *a = (int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100208 int mask;
209
210 a += nr >> 5;
211 mask = 1 << (nr & 0x1f);
212 return ((mask & *a) != 0);
213}
214
215#define test_bit(nr,addr) \
216(__builtin_constant_p(nr) ? \
217 __constant_test_bit((nr),(addr)) : \
218 __test_bit((nr),(addr)))
219
220#define find_first_zero_bit(addr, size) \
221 find_next_zero_bit((addr), (size), 0)
222
223static __inline__ int find_next_zero_bit(void *addr, int size, int offset)
224{
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800225 unsigned long *p = ((unsigned long *)addr) + (offset >> 5);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100226 unsigned long result = offset & ~31UL;
227 unsigned long tmp;
228
229 if (offset >= size)
230 return size;
231 size -= result;
232 offset &= 31UL;
233 if (offset) {
234 tmp = *(p++);
235 tmp |= ~0UL >> (32 - offset);
236 if (size < 32)
237 goto found_first;
238 if (~tmp)
239 goto found_middle;
240 size -= 32;
241 result += 32;
242 }
243 while (size & ~31UL) {
244 if (~(tmp = *(p++)))
245 goto found_middle;
246 result += 32;
247 size -= 32;
248 }
249 if (!size)
250 return result;
251 tmp = *p;
252
253 found_first:
254 tmp |= ~0UL >> size;
255 found_middle:
256 return result + ffz(tmp);
257}
258
259/*
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100260 * hweightN: returns the hamming weight (i.e. the number
261 * of bits set) of a N-bit word
262 */
263
264#define hweight32(x) generic_hweight32(x)
265#define hweight16(x) generic_hweight16(x)
266#define hweight8(x) generic_hweight8(x)
267
268static __inline__ int ext2_set_bit(int nr, volatile void *addr)
269{
270 int mask, retval;
271 unsigned long flags;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800272 volatile unsigned char *ADDR = (unsigned char *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100273
274 ADDR += nr >> 3;
275 mask = 1 << (nr & 0x07);
Mike Frysingerd4d77302008-02-04 19:26:55 -0500276 local_irq_save(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100277 retval = (mask & *ADDR) != 0;
278 *ADDR |= mask;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500279 local_irq_restore(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100280 return retval;
281}
282
283static __inline__ int ext2_clear_bit(int nr, volatile void *addr)
284{
285 int mask, retval;
286 unsigned long flags;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800287 volatile unsigned char *ADDR = (unsigned char *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100288
289 ADDR += nr >> 3;
290 mask = 1 << (nr & 0x07);
Mike Frysingerd4d77302008-02-04 19:26:55 -0500291 local_irq_save(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100292 retval = (mask & *ADDR) != 0;
293 *ADDR &= ~mask;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500294 local_irq_restore(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100295 return retval;
296}
297
298static __inline__ int ext2_test_bit(int nr, const volatile void *addr)
299{
300 int mask;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800301 const volatile unsigned char *ADDR = (const unsigned char *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100302
303 ADDR += nr >> 3;
304 mask = 1 << (nr & 0x07);
305 return ((mask & *ADDR) != 0);
306}
307
308#define ext2_find_first_zero_bit(addr, size) \
309 ext2_find_next_zero_bit((addr), (size), 0)
310
311static __inline__ unsigned long ext2_find_next_zero_bit(void *addr,
312 unsigned long size,
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800313 unsigned long offset)
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100314{
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800315 unsigned long *p = ((unsigned long *)addr) + (offset >> 5);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100316 unsigned long result = offset & ~31UL;
317 unsigned long tmp;
318
319 if (offset >= size)
320 return size;
321 size -= result;
322 offset &= 31UL;
323 if (offset) {
324 tmp = *(p++);
325 tmp |= ~0UL >> (32 - offset);
326 if (size < 32)
327 goto found_first;
328 if (~tmp)
329 goto found_middle;
330 size -= 32;
331 result += 32;
332 }
333 while (size & ~31UL) {
334 if (~(tmp = *(p++)))
335 goto found_middle;
336 result += 32;
337 size -= 32;
338 }
339 if (!size)
340 return result;
341 tmp = *p;
342
343 found_first:
344 tmp |= ~0UL >> size;
345 found_middle:
346 return result + ffz(tmp);
347}
348
349/* Bitmap functions for the minix filesystem. */
350#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
351#define minix_set_bit(nr,addr) set_bit(nr,addr)
352#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
353#define minix_test_bit(nr,addr) test_bit(nr,addr)
354#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
355
356#endif
357
358#endif