1 /* 2 * Copyright 2013 Broadcom Corporation. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 /* 8 * Bitfield operations 9 * 10 * These are generic bitfield operations which allow manipulation of variable 11 * width bitfields within a word. One use of this would be to use data tables 12 * to determine how to reprogram fields within R/W hardware registers. 13 * 14 * Example: 15 * 16 * old_reg_val 17 * +--------+----+---+--+-----+----------+ 18 * | | | | | old | | 19 * +--------+----+---+--+-----+----------+ 20 * 21 * new_reg_val 22 * +--------+----+---+--+-----+----------+ 23 * | | | | | new | | 24 * +--------+----+---+--+-----+----------+ 25 * 26 * mask = bitfield_mask(10, 5); 27 * old = bitfield_extract(old_reg_val, 10, 5); 28 * new_reg_val = bitfield_replace(old_reg_val, 10, 5, new); 29 * 30 * or 31 * 32 * mask = bitfield_mask(10, 5); 33 * old = bitfield_extract_by_mask(old_reg_val, mask); 34 * new_reg_val = bitfield_replace_by_mask(old_reg_val, mask, new); 35 * 36 * The numbers 10 and 5 could for example come from data 37 * tables which describe all bitfields in all registers. 38 */ 39 40 #include <linux/types.h> 41 42 /* Produces a mask of set bits covering a range of a uint value */ 43 static inline uint bitfield_mask(uint shift, uint width) 44 { 45 return ((1 << width) - 1) << shift; 46 } 47 48 /* Extract the value of a bitfield found within a given register value */ 49 static inline uint bitfield_extract(uint reg_val, uint shift, uint width) 50 { 51 return (reg_val & bitfield_mask(shift, width)) >> shift; 52 } 53 54 /* 55 * Replace the value of a bitfield found within a given register value 56 * Returns the newly modified uint value with the replaced field. 57 */ 58 static inline uint bitfield_replace(uint reg_val, uint shift, uint width, 59 uint bitfield_val) 60 { 61 uint mask = bitfield_mask(shift, width); 62 63 return (reg_val & ~mask) | ((bitfield_val << shift) & mask); 64 } 65 66 /* Produces a shift of the bitfield given a mask */ 67 static inline uint bitfield_shift(uint mask) 68 { 69 return mask ? ffs(mask) - 1 : 0; 70 } 71 72 /* Extract the value of a bitfield found within a given register value */ 73 static inline uint bitfield_extract_by_mask(uint reg_val, uint mask) 74 { 75 uint shift = bitfield_shift(mask); 76 77 return (reg_val & mask) >> shift; 78 } 79 80 /* 81 * Replace the value of a bitfield found within a given register value 82 * Returns the newly modified uint value with the replaced field. 83 */ 84 static inline uint bitfield_replace_by_mask(uint reg_val, uint mask, 85 uint bitfield_val) 86 { 87 uint shift = bitfield_shift(mask); 88 89 return (reg_val & ~mask) | ((bitfield_val << shift) & mask); 90 } 91