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 */ 43static 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 */ 49static 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 */ 58static 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 */ 67static 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 */ 73static 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 */ 84static 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