blob: cd7e3564595e2ba1bb8eec13e78394024091cdd5 [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>
18
19#ifdef __KERNEL__
20/*
21 * Function prototypes to keep gcc -Wall happy
22 */
23
24/*
25 * The __ functions are not atomic
26 */
27
28/*
29 * ffz = Find First Zero in word. Undefined if no zero exists,
30 * so code should check against ~0UL first..
31 */
32static __inline__ unsigned long ffz(unsigned long word)
33{
34 unsigned long result = 0;
35
36 while (word & 1) {
37 result++;
38 word >>= 1;
39 }
40 return result;
41}
42
43static __inline__ void set_bit(int nr, volatile void *addr)
44{
Aubrey.Li3f0606a2007-03-09 13:38:44 +080045 int *a = (int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010046 int mask;
47 unsigned long flags;
48
49 a += nr >> 5;
50 mask = 1 << (nr & 0x1f);
Mike Frysingerd4d77302008-02-04 19:26:55 -050051 local_irq_save(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010052 *a |= mask;
Mike Frysingerd4d77302008-02-04 19:26:55 -050053 local_irq_restore(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010054}
55
56static __inline__ void __set_bit(int nr, volatile void *addr)
57{
Aubrey.Li3f0606a2007-03-09 13:38:44 +080058 int *a = (int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010059 int mask;
60
61 a += nr >> 5;
62 mask = 1 << (nr & 0x1f);
63 *a |= mask;
64}
Simon Kagstrom0413cfe2009-09-17 15:15:52 +020065#define PLATFORM__SET_BIT
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010066
67/*
68 * clear_bit() doesn't provide any barrier for the compiler.
69 */
70#define smp_mb__before_clear_bit() barrier()
71#define smp_mb__after_clear_bit() barrier()
72
73static __inline__ void clear_bit(int nr, volatile void *addr)
74{
Aubrey.Li3f0606a2007-03-09 13:38:44 +080075 int *a = (int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010076 int mask;
77 unsigned long flags;
78
79 a += nr >> 5;
80 mask = 1 << (nr & 0x1f);
Mike Frysingerd4d77302008-02-04 19:26:55 -050081 local_irq_save(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010082 *a &= ~mask;
Mike Frysingerd4d77302008-02-04 19:26:55 -050083 local_irq_restore(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010084}
85
86static __inline__ void change_bit(int nr, volatile void *addr)
87{
88 int mask, flags;
Aubrey.Li3f0606a2007-03-09 13:38:44 +080089 unsigned long *ADDR = (unsigned long *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010090
91 ADDR += nr >> 5;
92 mask = 1 << (nr & 31);
Mike Frysingerd4d77302008-02-04 19:26:55 -050093 local_irq_save(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010094 *ADDR ^= mask;
Mike Frysingerd4d77302008-02-04 19:26:55 -050095 local_irq_restore(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +010096}
97
98static __inline__ void __change_bit(int nr, volatile void *addr)
99{
100 int mask;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800101 unsigned long *ADDR = (unsigned long *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100102
103 ADDR += nr >> 5;
104 mask = 1 << (nr & 31);
105 *ADDR ^= mask;
106}
107
108static __inline__ int test_and_set_bit(int nr, volatile void *addr)
109{
110 int mask, retval;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800111 volatile unsigned int *a = (volatile unsigned int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100112 unsigned long flags;
113
114 a += nr >> 5;
115 mask = 1 << (nr & 0x1f);
Mike Frysingerd4d77302008-02-04 19:26:55 -0500116 local_irq_save(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100117 retval = (mask & *a) != 0;
118 *a |= mask;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500119 local_irq_restore(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100120
121 return retval;
122}
123
124static __inline__ int __test_and_set_bit(int nr, volatile void *addr)
125{
126 int mask, retval;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800127 volatile unsigned int *a = (volatile unsigned int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100128
129 a += nr >> 5;
130 mask = 1 << (nr & 0x1f);
131 retval = (mask & *a) != 0;
132 *a |= mask;
133 return retval;
134}
135
136static __inline__ int test_and_clear_bit(int nr, volatile void *addr)
137{
138 int mask, retval;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800139 volatile unsigned int *a = (volatile unsigned int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100140 unsigned long flags;
141
142 a += nr >> 5;
143 mask = 1 << (nr & 0x1f);
Mike Frysingerd4d77302008-02-04 19:26:55 -0500144 local_irq_save(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100145 retval = (mask & *a) != 0;
146 *a &= ~mask;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500147 local_irq_restore(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100148
149 return retval;
150}
151
152static __inline__ int __test_and_clear_bit(int nr, volatile void *addr)
153{
154 int mask, retval;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800155 volatile unsigned int *a = (volatile unsigned int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100156
157 a += nr >> 5;
158 mask = 1 << (nr & 0x1f);
159 retval = (mask & *a) != 0;
160 *a &= ~mask;
161 return retval;
162}
163
164static __inline__ int test_and_change_bit(int nr, volatile void *addr)
165{
166 int mask, retval;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800167 volatile unsigned int *a = (volatile unsigned int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100168 unsigned long flags;
169
170 a += nr >> 5;
171 mask = 1 << (nr & 0x1f);
Mike Frysingerd4d77302008-02-04 19:26:55 -0500172 local_irq_save(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100173 retval = (mask & *a) != 0;
174 *a ^= mask;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500175 local_irq_restore(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100176
177 return retval;
178}
179
180static __inline__ int __test_and_change_bit(int nr, volatile void *addr)
181{
182 int mask, retval;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800183 volatile unsigned int *a = (volatile unsigned int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100184
185 a += nr >> 5;
186 mask = 1 << (nr & 0x1f);
187 retval = (mask & *a) != 0;
188 *a ^= mask;
189 return retval;
190}
191
192/*
193 * This routine doesn't need to be atomic.
194 */
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800195static __inline__ int __constant_test_bit(int nr, const volatile void *addr)
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100196{
197 return ((1UL << (nr & 31)) &
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800198 (((const volatile unsigned int *)addr)[nr >> 5])) != 0;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100199}
200
201static __inline__ int __test_bit(int nr, volatile void *addr)
202{
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800203 int *a = (int *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100204 int mask;
205
206 a += nr >> 5;
207 mask = 1 << (nr & 0x1f);
208 return ((mask & *a) != 0);
209}
210
211#define test_bit(nr,addr) \
212(__builtin_constant_p(nr) ? \
213 __constant_test_bit((nr),(addr)) : \
214 __test_bit((nr),(addr)))
215
216#define find_first_zero_bit(addr, size) \
217 find_next_zero_bit((addr), (size), 0)
218
219static __inline__ int find_next_zero_bit(void *addr, int size, int offset)
220{
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800221 unsigned long *p = ((unsigned long *)addr) + (offset >> 5);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100222 unsigned long result = offset & ~31UL;
223 unsigned long tmp;
224
225 if (offset >= size)
226 return size;
227 size -= result;
228 offset &= 31UL;
229 if (offset) {
230 tmp = *(p++);
231 tmp |= ~0UL >> (32 - offset);
232 if (size < 32)
233 goto found_first;
234 if (~tmp)
235 goto found_middle;
236 size -= 32;
237 result += 32;
238 }
239 while (size & ~31UL) {
240 if (~(tmp = *(p++)))
241 goto found_middle;
242 result += 32;
243 size -= 32;
244 }
245 if (!size)
246 return result;
247 tmp = *p;
248
249 found_first:
250 tmp |= ~0UL >> size;
251 found_middle:
252 return result + ffz(tmp);
253}
254
255/*
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100256 * hweightN: returns the hamming weight (i.e. the number
257 * of bits set) of a N-bit word
258 */
259
260#define hweight32(x) generic_hweight32(x)
261#define hweight16(x) generic_hweight16(x)
262#define hweight8(x) generic_hweight8(x)
263
264static __inline__ int ext2_set_bit(int nr, volatile void *addr)
265{
266 int mask, retval;
267 unsigned long flags;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800268 volatile unsigned char *ADDR = (unsigned char *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100269
270 ADDR += nr >> 3;
271 mask = 1 << (nr & 0x07);
Mike Frysingerd4d77302008-02-04 19:26:55 -0500272 local_irq_save(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100273 retval = (mask & *ADDR) != 0;
274 *ADDR |= mask;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500275 local_irq_restore(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100276 return retval;
277}
278
279static __inline__ int ext2_clear_bit(int nr, volatile void *addr)
280{
281 int mask, retval;
282 unsigned long flags;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800283 volatile unsigned char *ADDR = (unsigned char *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100284
285 ADDR += nr >> 3;
286 mask = 1 << (nr & 0x07);
Mike Frysingerd4d77302008-02-04 19:26:55 -0500287 local_irq_save(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100288 retval = (mask & *ADDR) != 0;
289 *ADDR &= ~mask;
Mike Frysingerd4d77302008-02-04 19:26:55 -0500290 local_irq_restore(flags);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100291 return retval;
292}
293
294static __inline__ int ext2_test_bit(int nr, const volatile void *addr)
295{
296 int mask;
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800297 const volatile unsigned char *ADDR = (const unsigned char *)addr;
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100298
299 ADDR += nr >> 3;
300 mask = 1 << (nr & 0x07);
301 return ((mask & *ADDR) != 0);
302}
303
304#define ext2_find_first_zero_bit(addr, size) \
305 ext2_find_next_zero_bit((addr), (size), 0)
306
307static __inline__ unsigned long ext2_find_next_zero_bit(void *addr,
308 unsigned long size,
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800309 unsigned long offset)
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100310{
Aubrey.Li3f0606a2007-03-09 13:38:44 +0800311 unsigned long *p = ((unsigned long *)addr) + (offset >> 5);
Wolfgang Denk6cb142f2006-03-12 02:12:27 +0100312 unsigned long result = offset & ~31UL;
313 unsigned long tmp;
314
315 if (offset >= size)
316 return size;
317 size -= result;
318 offset &= 31UL;
319 if (offset) {
320 tmp = *(p++);
321 tmp |= ~0UL >> (32 - offset);
322 if (size < 32)
323 goto found_first;
324 if (~tmp)
325 goto found_middle;
326 size -= 32;
327 result += 32;
328 }
329 while (size & ~31UL) {
330 if (~(tmp = *(p++)))
331 goto found_middle;
332 result += 32;
333 size -= 32;
334 }
335 if (!size)
336 return result;
337 tmp = *p;
338
339 found_first:
340 tmp |= ~0UL >> size;
341 found_middle:
342 return result + ffz(tmp);
343}
344
345/* Bitmap functions for the minix filesystem. */
346#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
347#define minix_set_bit(nr,addr) set_bit(nr,addr)
348#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
349#define minix_test_bit(nr,addr) test_bit(nr,addr)
350#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
351
352#endif
353
354#endif