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/bitops.h> 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