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