bitfield.h 2.5 KB

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